mirror of
https://github.com/vmware-tanzu/velero.git
synced 2025-12-23 06:15:21 +00:00
show server version in ark version output using ServerStatusRequest CRD
Signed-off-by: Steve Kriss <steve@heptio.com>
This commit is contained in:
1
changelogs/unreleased/1116-skriss
Normal file
1
changelogs/unreleased/1116-skriss
Normal file
@@ -0,0 +1 @@
|
||||
add ServerStatusRequest CRD and show server version in `ark version` output
|
||||
@@ -163,6 +163,20 @@ spec:
|
||||
kind: VolumeSnapshotLocation
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: serverstatusrequests.ark.heptio.com
|
||||
labels:
|
||||
component: ark
|
||||
spec:
|
||||
group: ark.heptio.com
|
||||
version: v1
|
||||
scope: Namespaced
|
||||
names:
|
||||
plural: serverstatusrequests
|
||||
kind: ServerStatusRequest
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
|
||||
@@ -69,6 +69,7 @@ func CustomResources() map[string]typeInfo {
|
||||
"ResticRepository": newTypeInfo("resticrepositories", &ResticRepository{}, &ResticRepositoryList{}),
|
||||
"BackupStorageLocation": newTypeInfo("backupstoragelocations", &BackupStorageLocation{}, &BackupStorageLocationList{}),
|
||||
"VolumeSnapshotLocation": newTypeInfo("volumesnapshotlocations", &VolumeSnapshotLocation{}, &VolumeSnapshotLocationList{}),
|
||||
"ServerStatusRequest": newTypeInfo("serverstatusrequests", &ServerStatusRequest{}, &ServerStatusRequestList{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
pkg/apis/ark/v1/server_status_request.go
Normal file
68
pkg/apis/ark/v1/server_status_request.go
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2018 the Heptio Ark contributors.
|
||||
|
||||
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 v1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ServerStatusRequest is a request to access current status information about
|
||||
// the Ark server.
|
||||
type ServerStatusRequest struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
Spec ServerStatusRequestSpec `json:"spec"`
|
||||
Status ServerStatusRequestStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ServerStatusRequestSpec is the specification for a ServerStatusRequest.
|
||||
type ServerStatusRequestSpec struct {
|
||||
}
|
||||
|
||||
// ServerStatusRequestPhase represents the lifecycle phase of a ServerStatusRequest.
|
||||
type ServerStatusRequestPhase string
|
||||
|
||||
const (
|
||||
// ServerStatusRequestPhaseNew means the ServerStatusRequest has not been processed yet.
|
||||
ServerStatusRequestPhaseNew ServerStatusRequestPhase = "New"
|
||||
// ServerStatusRequestPhaseProcessed means the ServerStatusRequest has been processed.
|
||||
ServerStatusRequestPhaseProcessed ServerStatusRequestPhase = "Processed"
|
||||
)
|
||||
|
||||
// ServerStatusRequestStatus is the current status of a ServerStatusRequest.
|
||||
type ServerStatusRequestStatus struct {
|
||||
// Phase is the current lifecycle phase of the ServerStatusRequest.
|
||||
Phase ServerStatusRequestPhase `json:"phase"`
|
||||
|
||||
// ProcessedTimestamp is when the ServerStatusRequest was processed
|
||||
// by the ServerStatusRequestController.
|
||||
ProcessedTimestamp metav1.Time `json:"processedTimestamp"`
|
||||
|
||||
// ServerVersion is the Ark server version.
|
||||
ServerVersion string `json:"serverVersion"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ServerStatusRequestList is a list of ServerStatusRequests.
|
||||
type ServerStatusRequestList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
Items []ServerStatusRequest `json:"items"`
|
||||
}
|
||||
@@ -1235,6 +1235,100 @@ func (in *ScheduleStatus) DeepCopy() *ScheduleStatus {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerStatusRequest) DeepCopyInto(out *ServerStatusRequest) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatusRequest.
|
||||
func (in *ServerStatusRequest) DeepCopy() *ServerStatusRequest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServerStatusRequest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ServerStatusRequest) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerStatusRequestList) DeepCopyInto(out *ServerStatusRequestList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ServerStatusRequest, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatusRequestList.
|
||||
func (in *ServerStatusRequestList) DeepCopy() *ServerStatusRequestList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServerStatusRequestList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ServerStatusRequestList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerStatusRequestSpec) DeepCopyInto(out *ServerStatusRequestSpec) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatusRequestSpec.
|
||||
func (in *ServerStatusRequestSpec) DeepCopy() *ServerStatusRequestSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServerStatusRequestSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerStatusRequestStatus) DeepCopyInto(out *ServerStatusRequestStatus) {
|
||||
*out = *in
|
||||
in.ProcessedTimestamp.DeepCopyInto(&out.ProcessedTimestamp)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatusRequestStatus.
|
||||
func (in *ServerStatusRequestStatus) DeepCopy() *ServerStatusRequestStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServerStatusRequestStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StorageType) DeepCopyInto(out *StorageType) {
|
||||
*out = *in
|
||||
|
||||
@@ -62,7 +62,7 @@ operations can also be performed as 'ark backup get' and 'ark schedule create'.`
|
||||
schedule.NewCommand(f),
|
||||
restore.NewCommand(f),
|
||||
server.NewCommand(),
|
||||
version.NewCommand(),
|
||||
version.NewCommand(f),
|
||||
get.NewCommand(f),
|
||||
describe.NewCommand(f),
|
||||
create.NewCommand(f),
|
||||
|
||||
@@ -681,6 +681,17 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
serverStatusRequestController := controller.NewServerStatusRequestController(
|
||||
s.logger,
|
||||
s.arkClient.ArkV1(),
|
||||
s.sharedInformerFactory.Ark().V1().ServerStatusRequests(),
|
||||
)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
serverStatusRequestController.Run(ctx, 1)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
// SHARED INFORMERS HAVE TO BE STARTED AFTER ALL CONTROLLERS
|
||||
go s.sharedInformerFactory.Start(ctx.Done())
|
||||
|
||||
|
||||
@@ -18,21 +18,133 @@ package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
"github.com/heptio/ark/pkg/buildinfo"
|
||||
"github.com/heptio/ark/pkg/client"
|
||||
"github.com/heptio/ark/pkg/cmd"
|
||||
arkv1client "github.com/heptio/ark/pkg/generated/clientset/versioned/typed/ark/v1"
|
||||
"github.com/heptio/ark/pkg/serverstatusrequest"
|
||||
)
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
func NewCommand(f client.Factory) *cobra.Command {
|
||||
clientOnly := false
|
||||
serverStatusGetter := &defaultServerStatusGetter{
|
||||
namespace: f.Namespace(),
|
||||
timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the ark version and associated image",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("Version: %s\n", buildinfo.Version)
|
||||
fmt.Printf("Git commit: %s\n", buildinfo.FormattedGitSHA())
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
var arkClient arkv1client.ServerStatusRequestsGetter
|
||||
|
||||
if !clientOnly {
|
||||
client, err := f.Client()
|
||||
cmd.CheckError(err)
|
||||
|
||||
arkClient = client.ArkV1()
|
||||
}
|
||||
|
||||
printVersion(os.Stdout, clientOnly, arkClient, 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 ark client version, not server version")
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func printVersion(w io.Writer, clientOnly bool, client arkv1client.ServerStatusRequestsGetter, serverStatusGetter serverStatusGetter) {
|
||||
fmt.Fprintln(w, "Client:")
|
||||
fmt.Fprintf(w, "\tVersion: %s\n", buildinfo.Version)
|
||||
fmt.Fprintf(w, "\tGit commit: %s\n", buildinfo.FormattedGitSHA())
|
||||
|
||||
if clientOnly {
|
||||
return
|
||||
}
|
||||
|
||||
serverStatus, err := serverStatusGetter.getServerStatus(client)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "<error getting server version: %s>\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, "Server:")
|
||||
fmt.Fprintf(w, "\tVersion: %s\n", serverStatus.Status.ServerVersion)
|
||||
}
|
||||
|
||||
type serverStatusGetter interface {
|
||||
getServerStatus(client arkv1client.ServerStatusRequestsGetter) (*arkv1api.ServerStatusRequest, error)
|
||||
}
|
||||
|
||||
type defaultServerStatusGetter struct {
|
||||
namespace string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func (g *defaultServerStatusGetter) getServerStatus(client arkv1client.ServerStatusRequestsGetter) (*arkv1api.ServerStatusRequest, error) {
|
||||
req := serverstatusrequest.NewBuilder().Namespace(g.namespace).GenerateName("ark-cli-").Build()
|
||||
|
||||
created, err := client.ServerStatusRequests(g.namespace).Create(req)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
defer client.ServerStatusRequests(g.namespace).Delete(created.Name, nil)
|
||||
|
||||
listOptions := metav1.ListOptions{
|
||||
// TODO: once the minimum supported Kubernetes version is v1.9.0, uncomment the following line.
|
||||
// See http://issue.k8s.io/51046 for details.
|
||||
//FieldSelector: "metadata.name=" + req.Name
|
||||
ResourceVersion: created.ResourceVersion,
|
||||
}
|
||||
watcher, err := client.ServerStatusRequests(g.namespace).Watch(listOptions)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
defer watcher.Stop()
|
||||
|
||||
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.(*arkv1api.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 == arkv1api.ServerStatusRequestPhaseProcessed {
|
||||
req = updated
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
129
pkg/cmd/version/version_test.go
Normal file
129
pkg/cmd/version/version_test.go
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2019 the Heptio Ark contributors.
|
||||
|
||||
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 version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
arkv1 "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
"github.com/heptio/ark/pkg/buildinfo"
|
||||
"github.com/heptio/ark/pkg/generated/clientset/versioned/fake"
|
||||
v1 "github.com/heptio/ark/pkg/generated/clientset/versioned/typed/ark/v1"
|
||||
"github.com/heptio/ark/pkg/serverstatusrequest"
|
||||
)
|
||||
|
||||
func TestPrintVersion(t *testing.T) {
|
||||
// set up some non-empty buildinfo values, but put them back to their
|
||||
// defaults at the end of the test
|
||||
var (
|
||||
origVersion = buildinfo.Version
|
||||
origGitSHA = buildinfo.GitSHA
|
||||
origGitTreeState = buildinfo.GitTreeState
|
||||
)
|
||||
defer func() {
|
||||
buildinfo.Version = origVersion
|
||||
buildinfo.GitSHA = origGitSHA
|
||||
buildinfo.GitTreeState = origGitTreeState
|
||||
}()
|
||||
buildinfo.Version = "v1.0.0"
|
||||
buildinfo.GitSHA = "somegitsha"
|
||||
buildinfo.GitTreeState = "dirty"
|
||||
|
||||
clientVersion := fmt.Sprintf("Client:\n\tVersion: %s\n\tGit commit: %s\n", buildinfo.Version, buildinfo.FormattedGitSHA())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clientOnly bool
|
||||
serverStatusRequest *arkv1.ServerStatusRequest
|
||||
getterError error
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "client-only",
|
||||
clientOnly: true,
|
||||
want: clientVersion,
|
||||
},
|
||||
{
|
||||
name: "server status getter error",
|
||||
clientOnly: false,
|
||||
serverStatusRequest: nil,
|
||||
getterError: errors.New("an error"),
|
||||
want: clientVersion + "<error getting server version: an error>\n",
|
||||
},
|
||||
{
|
||||
name: "server status getter returns normally",
|
||||
clientOnly: false,
|
||||
serverStatusRequest: serverstatusrequest.NewBuilder().ServerVersion("v1.0.1").Build(),
|
||||
getterError: nil,
|
||||
want: clientVersion + "Server:\n\tVersion: v1.0.1\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var (
|
||||
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.ArkV1()).Return(tc.serverStatusRequest, tc.getterError)
|
||||
}
|
||||
|
||||
printVersion(buf, tc.clientOnly, client.ArkV1(), serverStatusGetter)
|
||||
|
||||
assert.Equal(t, tc.want, buf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// serverStatusGetter is an autogenerated mock type for the serverStatusGetter type
|
||||
type mockServerStatusGetter struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// getServerStatus provides a mock function with given fields: client
|
||||
func (_m *mockServerStatusGetter) getServerStatus(client v1.ServerStatusRequestsGetter) (*arkv1.ServerStatusRequest, error) {
|
||||
ret := _m.Called(client)
|
||||
|
||||
var r0 *arkv1.ServerStatusRequest
|
||||
if rf, ok := ret.Get(0).(func(v1.ServerStatusRequestsGetter) *arkv1.ServerStatusRequest); ok {
|
||||
r0 = rf(client)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*arkv1.ServerStatusRequest)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(v1.ServerStatusRequestsGetter) error); ok {
|
||||
r1 = rf(client)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
118
pkg/controller/server_status_request_controller.go
Normal file
118
pkg/controller/server_status_request_controller.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright 2018 the Heptio Ark contributors.
|
||||
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
arkv1client "github.com/heptio/ark/pkg/generated/clientset/versioned/typed/ark/v1"
|
||||
arkv1informers "github.com/heptio/ark/pkg/generated/informers/externalversions/ark/v1"
|
||||
arkv1listers "github.com/heptio/ark/pkg/generated/listers/ark/v1"
|
||||
"github.com/heptio/ark/pkg/serverstatusrequest"
|
||||
kubeutil "github.com/heptio/ark/pkg/util/kube"
|
||||
)
|
||||
|
||||
const statusRequestResyncPeriod = 5 * time.Minute
|
||||
|
||||
type statusRequestController struct {
|
||||
*genericController
|
||||
|
||||
client arkv1client.ServerStatusRequestsGetter
|
||||
lister arkv1listers.ServerStatusRequestLister
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
func NewServerStatusRequestController(
|
||||
logger logrus.FieldLogger,
|
||||
client arkv1client.ServerStatusRequestsGetter,
|
||||
informer arkv1informers.ServerStatusRequestInformer,
|
||||
) *statusRequestController {
|
||||
c := &statusRequestController{
|
||||
genericController: newGenericController("serverstatusrequest", logger),
|
||||
client: client,
|
||||
lister: informer.Lister(),
|
||||
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
c.syncHandler = c.processItem
|
||||
c.cacheSyncWaiters = append(c.cacheSyncWaiters, informer.Informer().HasSynced)
|
||||
|
||||
c.resyncFunc = c.enqueueAllItems
|
||||
c.resyncPeriod = statusRequestResyncPeriod
|
||||
|
||||
informer.Informer().AddEventHandler(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
req := obj.(*arkv1api.ServerStatusRequest)
|
||||
key := kubeutil.NamespaceAndName(req)
|
||||
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"serverStatusRequest": key,
|
||||
"phase": req.Status.Phase,
|
||||
}).Debug("Enqueueing server status request")
|
||||
|
||||
c.queue.Add(key)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *statusRequestController) processItem(key string) error {
|
||||
log := c.logger.WithField("key", key)
|
||||
|
||||
log.Debug("Running processItem")
|
||||
ns, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error splitting queue key")
|
||||
}
|
||||
|
||||
log.Debug("Getting ServerStatusRequest")
|
||||
req, err := c.lister.ServerStatusRequests(ns).Get(name)
|
||||
// server status request no longer exists
|
||||
if apierrors.IsNotFound(err) {
|
||||
log.WithError(err).Debug("ServerStatusRequest not found")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error getting ServerStatusRequest")
|
||||
}
|
||||
|
||||
return serverstatusrequest.Process(req.DeepCopy(), c.client, c.clock, log)
|
||||
}
|
||||
|
||||
func (c *statusRequestController) enqueueAllItems() {
|
||||
items, err := c.lister.List(labels.Everything())
|
||||
if err != nil {
|
||||
c.logger.WithError(err).Error("Error listing all server status requests")
|
||||
return
|
||||
}
|
||||
|
||||
for _, req := range items {
|
||||
c.enqueue(req)
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ type ArkV1Interface interface {
|
||||
ResticRepositoriesGetter
|
||||
RestoresGetter
|
||||
SchedulesGetter
|
||||
ServerStatusRequestsGetter
|
||||
VolumeSnapshotLocationsGetter
|
||||
}
|
||||
|
||||
@@ -80,6 +81,10 @@ func (c *ArkV1Client) Schedules(namespace string) ScheduleInterface {
|
||||
return newSchedules(c, namespace)
|
||||
}
|
||||
|
||||
func (c *ArkV1Client) ServerStatusRequests(namespace string) ServerStatusRequestInterface {
|
||||
return newServerStatusRequests(c, namespace)
|
||||
}
|
||||
|
||||
func (c *ArkV1Client) VolumeSnapshotLocations(namespace string) VolumeSnapshotLocationInterface {
|
||||
return newVolumeSnapshotLocations(c, namespace)
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ func (c *FakeArkV1) Schedules(namespace string) v1.ScheduleInterface {
|
||||
return &FakeSchedules{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeArkV1) ServerStatusRequests(namespace string) v1.ServerStatusRequestInterface {
|
||||
return &FakeServerStatusRequests{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeArkV1) VolumeSnapshotLocations(namespace string) v1.VolumeSnapshotLocationInterface {
|
||||
return &FakeVolumeSnapshotLocations{c, namespace}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright the Heptio Ark contributors.
|
||||
|
||||
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 client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
ark_v1 "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeServerStatusRequests implements ServerStatusRequestInterface
|
||||
type FakeServerStatusRequests struct {
|
||||
Fake *FakeArkV1
|
||||
ns string
|
||||
}
|
||||
|
||||
var serverstatusrequestsResource = schema.GroupVersionResource{Group: "ark.heptio.com", Version: "v1", Resource: "serverstatusrequests"}
|
||||
|
||||
var serverstatusrequestsKind = schema.GroupVersionKind{Group: "ark.heptio.com", Version: "v1", Kind: "ServerStatusRequest"}
|
||||
|
||||
// Get takes name of the serverStatusRequest, and returns the corresponding serverStatusRequest object, and an error if there is any.
|
||||
func (c *FakeServerStatusRequests) Get(name string, options v1.GetOptions) (result *ark_v1.ServerStatusRequest, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(serverstatusrequestsResource, c.ns, name), &ark_v1.ServerStatusRequest{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*ark_v1.ServerStatusRequest), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of ServerStatusRequests that match those selectors.
|
||||
func (c *FakeServerStatusRequests) List(opts v1.ListOptions) (result *ark_v1.ServerStatusRequestList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(serverstatusrequestsResource, serverstatusrequestsKind, c.ns, opts), &ark_v1.ServerStatusRequestList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &ark_v1.ServerStatusRequestList{ListMeta: obj.(*ark_v1.ServerStatusRequestList).ListMeta}
|
||||
for _, item := range obj.(*ark_v1.ServerStatusRequestList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested serverStatusRequests.
|
||||
func (c *FakeServerStatusRequests) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(serverstatusrequestsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a serverStatusRequest and creates it. Returns the server's representation of the serverStatusRequest, and an error, if there is any.
|
||||
func (c *FakeServerStatusRequests) Create(serverStatusRequest *ark_v1.ServerStatusRequest) (result *ark_v1.ServerStatusRequest, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(serverstatusrequestsResource, c.ns, serverStatusRequest), &ark_v1.ServerStatusRequest{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*ark_v1.ServerStatusRequest), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a serverStatusRequest and updates it. Returns the server's representation of the serverStatusRequest, and an error, if there is any.
|
||||
func (c *FakeServerStatusRequests) Update(serverStatusRequest *ark_v1.ServerStatusRequest) (result *ark_v1.ServerStatusRequest, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(serverstatusrequestsResource, c.ns, serverStatusRequest), &ark_v1.ServerStatusRequest{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*ark_v1.ServerStatusRequest), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeServerStatusRequests) UpdateStatus(serverStatusRequest *ark_v1.ServerStatusRequest) (*ark_v1.ServerStatusRequest, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(serverstatusrequestsResource, "status", c.ns, serverStatusRequest), &ark_v1.ServerStatusRequest{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*ark_v1.ServerStatusRequest), err
|
||||
}
|
||||
|
||||
// Delete takes name of the serverStatusRequest and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeServerStatusRequests) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(serverstatusrequestsResource, c.ns, name), &ark_v1.ServerStatusRequest{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeServerStatusRequests) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(serverstatusrequestsResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &ark_v1.ServerStatusRequestList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched serverStatusRequest.
|
||||
func (c *FakeServerStatusRequests) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *ark_v1.ServerStatusRequest, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(serverstatusrequestsResource, c.ns, name, data, subresources...), &ark_v1.ServerStatusRequest{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*ark_v1.ServerStatusRequest), err
|
||||
}
|
||||
@@ -36,4 +36,6 @@ type RestoreExpansion interface{}
|
||||
|
||||
type ScheduleExpansion interface{}
|
||||
|
||||
type ServerStatusRequestExpansion interface{}
|
||||
|
||||
type VolumeSnapshotLocationExpansion interface{}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
Copyright the Heptio Ark contributors.
|
||||
|
||||
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 client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
scheme "github.com/heptio/ark/pkg/generated/clientset/versioned/scheme"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// ServerStatusRequestsGetter has a method to return a ServerStatusRequestInterface.
|
||||
// A group's client should implement this interface.
|
||||
type ServerStatusRequestsGetter interface {
|
||||
ServerStatusRequests(namespace string) ServerStatusRequestInterface
|
||||
}
|
||||
|
||||
// ServerStatusRequestInterface has methods to work with ServerStatusRequest resources.
|
||||
type ServerStatusRequestInterface interface {
|
||||
Create(*v1.ServerStatusRequest) (*v1.ServerStatusRequest, error)
|
||||
Update(*v1.ServerStatusRequest) (*v1.ServerStatusRequest, error)
|
||||
UpdateStatus(*v1.ServerStatusRequest) (*v1.ServerStatusRequest, error)
|
||||
Delete(name string, options *meta_v1.DeleteOptions) error
|
||||
DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error
|
||||
Get(name string, options meta_v1.GetOptions) (*v1.ServerStatusRequest, error)
|
||||
List(opts meta_v1.ListOptions) (*v1.ServerStatusRequestList, error)
|
||||
Watch(opts meta_v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ServerStatusRequest, err error)
|
||||
ServerStatusRequestExpansion
|
||||
}
|
||||
|
||||
// serverStatusRequests implements ServerStatusRequestInterface
|
||||
type serverStatusRequests struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newServerStatusRequests returns a ServerStatusRequests
|
||||
func newServerStatusRequests(c *ArkV1Client, namespace string) *serverStatusRequests {
|
||||
return &serverStatusRequests{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the serverStatusRequest, and returns the corresponding serverStatusRequest object, and an error if there is any.
|
||||
func (c *serverStatusRequests) Get(name string, options meta_v1.GetOptions) (result *v1.ServerStatusRequest, err error) {
|
||||
result = &v1.ServerStatusRequest{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of ServerStatusRequests that match those selectors.
|
||||
func (c *serverStatusRequests) List(opts meta_v1.ListOptions) (result *v1.ServerStatusRequestList, err error) {
|
||||
result = &v1.ServerStatusRequestList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested serverStatusRequests.
|
||||
func (c *serverStatusRequests) Watch(opts meta_v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a serverStatusRequest and creates it. Returns the server's representation of the serverStatusRequest, and an error, if there is any.
|
||||
func (c *serverStatusRequests) Create(serverStatusRequest *v1.ServerStatusRequest) (result *v1.ServerStatusRequest, err error) {
|
||||
result = &v1.ServerStatusRequest{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
Body(serverStatusRequest).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a serverStatusRequest and updates it. Returns the server's representation of the serverStatusRequest, and an error, if there is any.
|
||||
func (c *serverStatusRequests) Update(serverStatusRequest *v1.ServerStatusRequest) (result *v1.ServerStatusRequest, err error) {
|
||||
result = &v1.ServerStatusRequest{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
Name(serverStatusRequest.Name).
|
||||
Body(serverStatusRequest).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *serverStatusRequests) UpdateStatus(serverStatusRequest *v1.ServerStatusRequest) (result *v1.ServerStatusRequest, err error) {
|
||||
result = &v1.ServerStatusRequest{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
Name(serverStatusRequest.Name).
|
||||
SubResource("status").
|
||||
Body(serverStatusRequest).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the serverStatusRequest and deletes it. Returns an error if one occurs.
|
||||
func (c *serverStatusRequests) Delete(name string, options *meta_v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *serverStatusRequests) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched serverStatusRequest.
|
||||
func (c *serverStatusRequests) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ServerStatusRequest, err error) {
|
||||
result = &v1.ServerStatusRequest{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("serverstatusrequests").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
@@ -42,6 +42,8 @@ type Interface interface {
|
||||
Restores() RestoreInformer
|
||||
// Schedules returns a ScheduleInformer.
|
||||
Schedules() ScheduleInformer
|
||||
// ServerStatusRequests returns a ServerStatusRequestInformer.
|
||||
ServerStatusRequests() ServerStatusRequestInformer
|
||||
// VolumeSnapshotLocations returns a VolumeSnapshotLocationInformer.
|
||||
VolumeSnapshotLocations() VolumeSnapshotLocationInformer
|
||||
}
|
||||
@@ -102,6 +104,11 @@ func (v *version) Schedules() ScheduleInformer {
|
||||
return &scheduleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// ServerStatusRequests returns a ServerStatusRequestInformer.
|
||||
func (v *version) ServerStatusRequests() ServerStatusRequestInformer {
|
||||
return &serverStatusRequestInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// VolumeSnapshotLocations returns a VolumeSnapshotLocationInformer.
|
||||
func (v *version) VolumeSnapshotLocations() VolumeSnapshotLocationInformer {
|
||||
return &volumeSnapshotLocationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright the Heptio Ark contributors.
|
||||
|
||||
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 (
|
||||
time "time"
|
||||
|
||||
ark_v1 "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
versioned "github.com/heptio/ark/pkg/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/heptio/ark/pkg/generated/informers/externalversions/internalinterfaces"
|
||||
v1 "github.com/heptio/ark/pkg/generated/listers/ark/v1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// ServerStatusRequestInformer provides access to a shared informer and lister for
|
||||
// ServerStatusRequests.
|
||||
type ServerStatusRequestInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1.ServerStatusRequestLister
|
||||
}
|
||||
|
||||
type serverStatusRequestInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewServerStatusRequestInformer constructs a new informer for ServerStatusRequest 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 NewServerStatusRequestInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredServerStatusRequestInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredServerStatusRequestInformer constructs a new informer for ServerStatusRequest 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 NewFilteredServerStatusRequestInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ArkV1().ServerStatusRequests(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ArkV1().ServerStatusRequests(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&ark_v1.ServerStatusRequest{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *serverStatusRequestInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredServerStatusRequestInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *serverStatusRequestInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&ark_v1.ServerStatusRequest{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *serverStatusRequestInformer) Lister() v1.ServerStatusRequestLister {
|
||||
return v1.NewServerStatusRequestLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -71,6 +71,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ark().V1().Restores().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("schedules"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ark().V1().Schedules().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("serverstatusrequests"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ark().V1().ServerStatusRequests().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("volumesnapshotlocations"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ark().V1().VolumeSnapshotLocations().Informer()}, nil
|
||||
|
||||
|
||||
@@ -90,6 +90,14 @@ type ScheduleListerExpansion interface{}
|
||||
// ScheduleNamespaceLister.
|
||||
type ScheduleNamespaceListerExpansion interface{}
|
||||
|
||||
// ServerStatusRequestListerExpansion allows custom methods to be added to
|
||||
// ServerStatusRequestLister.
|
||||
type ServerStatusRequestListerExpansion interface{}
|
||||
|
||||
// ServerStatusRequestNamespaceListerExpansion allows custom methods to be added to
|
||||
// ServerStatusRequestNamespaceLister.
|
||||
type ServerStatusRequestNamespaceListerExpansion interface{}
|
||||
|
||||
// VolumeSnapshotLocationListerExpansion allows custom methods to be added to
|
||||
// VolumeSnapshotLocationLister.
|
||||
type VolumeSnapshotLocationListerExpansion interface{}
|
||||
|
||||
94
pkg/generated/listers/ark/v1/serverstatusrequest.go
Normal file
94
pkg/generated/listers/ark/v1/serverstatusrequest.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright the Heptio Ark contributors.
|
||||
|
||||
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 lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// ServerStatusRequestLister helps list ServerStatusRequests.
|
||||
type ServerStatusRequestLister interface {
|
||||
// List lists all ServerStatusRequests in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1.ServerStatusRequest, err error)
|
||||
// ServerStatusRequests returns an object that can list and get ServerStatusRequests.
|
||||
ServerStatusRequests(namespace string) ServerStatusRequestNamespaceLister
|
||||
ServerStatusRequestListerExpansion
|
||||
}
|
||||
|
||||
// serverStatusRequestLister implements the ServerStatusRequestLister interface.
|
||||
type serverStatusRequestLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewServerStatusRequestLister returns a new ServerStatusRequestLister.
|
||||
func NewServerStatusRequestLister(indexer cache.Indexer) ServerStatusRequestLister {
|
||||
return &serverStatusRequestLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all ServerStatusRequests in the indexer.
|
||||
func (s *serverStatusRequestLister) List(selector labels.Selector) (ret []*v1.ServerStatusRequest, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1.ServerStatusRequest))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// ServerStatusRequests returns an object that can list and get ServerStatusRequests.
|
||||
func (s *serverStatusRequestLister) ServerStatusRequests(namespace string) ServerStatusRequestNamespaceLister {
|
||||
return serverStatusRequestNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// ServerStatusRequestNamespaceLister helps list and get ServerStatusRequests.
|
||||
type ServerStatusRequestNamespaceLister interface {
|
||||
// List lists all ServerStatusRequests in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1.ServerStatusRequest, err error)
|
||||
// Get retrieves the ServerStatusRequest from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1.ServerStatusRequest, error)
|
||||
ServerStatusRequestNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// serverStatusRequestNamespaceLister implements the ServerStatusRequestNamespaceLister
|
||||
// interface.
|
||||
type serverStatusRequestNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all ServerStatusRequests in the indexer for a given namespace.
|
||||
func (s serverStatusRequestNamespaceLister) List(selector labels.Selector) (ret []*v1.ServerStatusRequest, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1.ServerStatusRequest))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the ServerStatusRequest from the indexer for a given namespace and name.
|
||||
func (s serverStatusRequestNamespaceLister) Get(name string) (*v1.ServerStatusRequest, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1.Resource("serverstatusrequest"), name)
|
||||
}
|
||||
return obj.(*v1.ServerStatusRequest), nil
|
||||
}
|
||||
74
pkg/serverstatusrequest/builder.go
Normal file
74
pkg/serverstatusrequest/builder.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2018 the Heptio Ark contributors.
|
||||
|
||||
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 serverstatusrequest
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
serverStatusRequest arkv1api.ServerStatusRequest
|
||||
}
|
||||
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
serverStatusRequest: arkv1api.ServerStatusRequest{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: arkv1api.SchemeGroupVersion.String(),
|
||||
Kind: "ServerStatusRequest",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) Build() *arkv1api.ServerStatusRequest {
|
||||
return &b.serverStatusRequest
|
||||
}
|
||||
|
||||
func (b *Builder) Namespace(namespace string) *Builder {
|
||||
b.serverStatusRequest.Namespace = namespace
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) Name(name string) *Builder {
|
||||
b.serverStatusRequest.Name = name
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) GenerateName(name string) *Builder {
|
||||
b.serverStatusRequest.GenerateName = name
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) Phase(phase arkv1api.ServerStatusRequestPhase) *Builder {
|
||||
b.serverStatusRequest.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) ProcessedTimestamp(time time.Time) *Builder {
|
||||
b.serverStatusRequest.Status.ProcessedTimestamp.Time = time
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) ServerVersion(version string) *Builder {
|
||||
b.serverStatusRequest.Status.ServerVersion = version
|
||||
return b
|
||||
}
|
||||
90
pkg/serverstatusrequest/process.go
Normal file
90
pkg/serverstatusrequest/process.go
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2018 the Heptio Ark contributors.
|
||||
|
||||
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 serverstatusrequest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
|
||||
arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
"github.com/heptio/ark/pkg/buildinfo"
|
||||
arkv1client "github.com/heptio/ark/pkg/generated/clientset/versioned/typed/ark/v1"
|
||||
)
|
||||
|
||||
const ttl = time.Minute
|
||||
|
||||
// Process fills out new ServerStatusRequest objects and deletes processed ones
|
||||
// that have expired.
|
||||
func Process(req *arkv1api.ServerStatusRequest, client arkv1client.ServerStatusRequestsGetter, clock clock.Clock, log logrus.FieldLogger) error {
|
||||
switch req.Status.Phase {
|
||||
case "", arkv1api.ServerStatusRequestPhaseNew:
|
||||
log.Info("Processing new ServerStatusRequest")
|
||||
return errors.WithStack(patch(client, req, func(req *arkv1api.ServerStatusRequest) {
|
||||
req.Status.ServerVersion = buildinfo.Version
|
||||
req.Status.ProcessedTimestamp.Time = clock.Now()
|
||||
req.Status.Phase = arkv1api.ServerStatusRequestPhaseProcessed
|
||||
}))
|
||||
case arkv1api.ServerStatusRequestPhaseProcessed:
|
||||
log.Debug("Checking whether ServerStatusRequest has expired")
|
||||
expiration := req.Status.ProcessedTimestamp.Add(ttl)
|
||||
if expiration.After(clock.Now()) {
|
||||
log.Debug("ServerStatusRequest has not expired")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("ServerStatusRequest has expired, deleting it")
|
||||
if err := client.ServerStatusRequests(req.Namespace).Delete(req.Name, nil); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return errors.Errorf("unexpected ServerStatusRequest phase %q", req.Status.Phase)
|
||||
}
|
||||
}
|
||||
|
||||
func patch(client arkv1client.ServerStatusRequestsGetter, req *arkv1api.ServerStatusRequest, updateFunc func(*arkv1api.ServerStatusRequest)) error {
|
||||
originalJSON, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
updateFunc(req)
|
||||
|
||||
updatedJSON, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
patchBytes, err := jsonpatch.CreateMergePatch(originalJSON, updatedJSON)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
_, err = client.ServerStatusRequests(req.Namespace).Patch(req.Name, types.MergePatchType, patchBytes)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
126
pkg/serverstatusrequest/process_test.go
Normal file
126
pkg/serverstatusrequest/process_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright 2018 the Heptio Ark contributors.
|
||||
|
||||
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 serverstatusrequest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
|
||||
arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
|
||||
"github.com/heptio/ark/pkg/buildinfo"
|
||||
"github.com/heptio/ark/pkg/generated/clientset/versioned/fake"
|
||||
)
|
||||
|
||||
func statusRequestBuilder() *Builder {
|
||||
return NewBuilder().Namespace(arkv1api.DefaultNamespace).Name("sr-1")
|
||||
}
|
||||
|
||||
func TestProcess(t *testing.T) {
|
||||
// now will be used to set the fake clock's time; capture
|
||||
// it here so it can be referenced in the test case defs.
|
||||
now, err := time.Parse(time.RFC1123, time.RFC1123)
|
||||
require.NoError(t, err)
|
||||
now = now.Local()
|
||||
|
||||
buildinfo.Version = "test-version-val"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
req *arkv1api.ServerStatusRequest
|
||||
expected *arkv1api.ServerStatusRequest
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "server status request with empty phase gets processed",
|
||||
req: statusRequestBuilder().Build(),
|
||||
expected: statusRequestBuilder().
|
||||
ServerVersion(buildinfo.Version).
|
||||
Phase(arkv1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now).
|
||||
Build(),
|
||||
},
|
||||
{
|
||||
name: "server status request with phase=New gets processed",
|
||||
req: statusRequestBuilder().
|
||||
Phase(arkv1api.ServerStatusRequestPhaseNew).
|
||||
Build(),
|
||||
expected: statusRequestBuilder().
|
||||
ServerVersion(buildinfo.Version).
|
||||
Phase(arkv1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now).
|
||||
Build(),
|
||||
},
|
||||
{
|
||||
name: "server status request with phase=Processed gets deleted if expired",
|
||||
req: statusRequestBuilder().
|
||||
Phase(arkv1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now.Add(-61 * time.Second)).
|
||||
Build(),
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "server status request with phase=Processed does not get deleted if not expired",
|
||||
req: statusRequestBuilder().
|
||||
Phase(arkv1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now.Add(-59 * time.Second)).
|
||||
Build(),
|
||||
expected: statusRequestBuilder().
|
||||
Phase(arkv1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now.Add(-59 * time.Second)).
|
||||
Build(),
|
||||
},
|
||||
{
|
||||
name: "server status request with invalid phase returns an error",
|
||||
req: statusRequestBuilder().
|
||||
Phase(arkv1api.ServerStatusRequestPhase("an-invalid-phase")).
|
||||
Build(),
|
||||
expected: statusRequestBuilder().
|
||||
Phase(arkv1api.ServerStatusRequestPhase("an-invalid-phase")).
|
||||
Build(),
|
||||
expectedErrMsg: "unexpected ServerStatusRequest phase \"an-invalid-phase\"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := fake.NewSimpleClientset(tc.req)
|
||||
|
||||
err := Process(tc.req, client.ArkV1(), clock.NewFakeClock(now), logrus.StandardLogger())
|
||||
if tc.expectedErrMsg == "" {
|
||||
assert.Nil(t, err)
|
||||
} else {
|
||||
assert.EqualError(t, err, tc.expectedErrMsg)
|
||||
}
|
||||
|
||||
res, err := client.ArkV1().ServerStatusRequests(tc.req.Namespace).Get(tc.req.Name, metav1.GetOptions{})
|
||||
if tc.expected == nil {
|
||||
assert.Nil(t, res)
|
||||
assert.True(t, apierrors.IsNotFound(err))
|
||||
} else {
|
||||
assert.Equal(t, tc.expected, res)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user