Add IPPool CR-based persistance

This adds persistance (to CRs) for Vino IPAM functionality.

This will be integrated with the controller in a follow-on patchset.

Change-Id: I5b2695df72d52890d315d3ab32c36f12377f857f
This commit is contained in:
Matt McEuen 2021-02-04 20:14:01 -06:00
parent 40d4804ad1
commit 1f6be5c0e4
5 changed files with 519 additions and 66 deletions

3
go.mod
View File

@ -7,6 +7,9 @@ require (
github.com/go-logr/logr v0.3.0
github.com/go-logr/zapr v0.2.0
github.com/metal3-io/baremetal-operator v0.0.0-20210111093319-93a6fd209b9a
github.com/golang/mock v1.4.4
github.com/kr/text v0.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/onsi/ginkgo v1.14.2
github.com/onsi/gomega v1.10.2
github.com/prometheus/common v0.10.0

3
go.sum
View File

@ -253,9 +253,12 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18h
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

View File

@ -15,33 +15,34 @@
package ipam
import (
"context"
"net"
"regexp"
"strings"
"unsafe"
vinov1 "vino/pkg/api/v1"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
vinov1 "vino/pkg/api/v1"
)
// Ipam provides IPAM reservation, backed by IPPool CRs
type Ipam struct {
Log logr.Logger
Scheme *runtime.Scheme
Client client.Client
ippools map[string]*vinov1.IPPoolSpec
Log logr.Logger
Client client.Client
Namespace string
}
// NewIpam initializes an empty IPAM configuration.
// TODO: persist and refresh state from the API server
// TODO: add ability to remove IP addresses and ranges
func NewIpam() *Ipam {
ippools := make(map[string]*vinov1.IPPoolSpec)
func NewIpam(logger logr.Logger, client client.Client, namespace string) *Ipam {
return &Ipam{
ippools: ippools,
Log: logger,
Client: client,
Namespace: namespace,
}
}
@ -65,39 +66,47 @@ func NewRange(start string, stop string) (vinov1.Range, error) {
// AddSubnetRange adds a range within a subnet for IP allocation
// TODO error: range overlaps with existing range or subnet overlaps with existing subnet
// TODO error: invalid range for subnet
func (i *Ipam) AddSubnetRange(subnet string, subnetRange vinov1.Range) error {
func (i *Ipam) AddSubnetRange(ctx context.Context, subnet string, subnetRange vinov1.Range) error {
logger := i.Log.WithValues("subnet", subnet, "subnetRange", subnetRange)
// Does the subnet already exist? (this is fine)
ippool, exists := i.ippools[subnet]
ippools, err := i.getIPPools(ctx)
if err != nil {
return err
}
ippool, exists := ippools[subnet]
if !exists {
logger.Info("IPAM creating subnet and adding range")
ippool = &vinov1.IPPoolSpec{
Subnet: subnet,
Ranges: []vinov1.Range{subnetRange},
Ranges: []vinov1.Range{},
AllocatedIPs: []string{},
}
i.ippools[subnet] = ippool
ippools[subnet] = ippool
} else {
logger.Info("IPAM subnet already exists; adding range")
// Does the subnet's requested range already exist? (this should fail)
exists = false
for _, r := range ippool.Ranges {
if r == subnetRange {
exists = true
break
return ErrSubnetRangeOverlapsWithExistingRange{Subnet: subnet, SubnetRange: subnetRange}
}
}
if exists {
return ErrSubnetRangeOverlapsWithExistingRange{Subnet: subnet, SubnetRange: subnetRange}
}
}
ippool.Ranges = append(ippool.Ranges, subnetRange)
err = i.applyIPPool(ctx, *ippool)
if err != nil {
return err
}
return nil
}
// AllocateIP allocates an IP from a range and return it
func (i *Ipam) AllocateIP(subnet string, subnetRange vinov1.Range) (string, error) {
// NOTE/TODO: this is not threadsafe, which is fine because
// the final impl will use the api server as the backend, not local.
ippool, exists := i.ippools[subnet]
func (i *Ipam) AllocateIP(ctx context.Context, subnet string, subnetRange vinov1.Range) (string, error) {
ippools, err := i.getIPPools(ctx)
if err != nil {
return "", err
}
ippool, exists := ippools[subnet]
if !exists {
return "", ErrSubnetNotAllocated{Subnet: subnet}
}
@ -117,7 +126,13 @@ func (i *Ipam) AllocateIP(subnet string, subnetRange vinov1.Range) (string, erro
if err != nil {
return "", err
}
i.Log.Info("Allocating IP", "ip", ip, "subnet", subnet, "subnetRange", subnetRange)
ippool.AllocatedIPs = append(ippool.AllocatedIPs, ip)
err = i.applyIPPool(ctx, *ippool)
if err != nil {
return "", err
}
return ip, nil
}
@ -126,7 +141,10 @@ func (i *Ipam) AllocateIP(subnet string, subnetRange vinov1.Range) (string, erro
// in use, converts it back to a string and returns it.
// It does not itself add it to the list of assigned IPs.
func findFreeIPInRange(ippool *vinov1.IPPoolSpec, subnetRange vinov1.Range) (string, error) {
allocatedIPSet := sliceToMap(ippool.AllocatedIPs)
allocatedIPSet, err := sliceToMap(ippool.AllocatedIPs)
if err != nil {
return "", err
}
intToString := intToIPv4String
if strings.Contains(ippool.Subnet, ":") {
intToString = intToIPv6String
@ -143,7 +161,7 @@ func findFreeIPInRange(ippool *vinov1.IPPoolSpec, subnetRange vinov1.Range) (str
}
for ip := start; ip <= stop; ip++ {
_, in := allocatedIPSet[intToString(ip)]
_, in := allocatedIPSet[ip]
if !in {
// Found an unallocated IP
return intToString(ip), nil
@ -152,14 +170,18 @@ func findFreeIPInRange(ippool *vinov1.IPPoolSpec, subnetRange vinov1.Range) (str
return "", ErrSubnetRangeExhausted{ippool.Subnet, subnetRange}
}
// Create a map[string]struct{} representation of a string slice,
// Create a map[uint64]struct{} representation of a string slice,
// for efficient set lookups
func sliceToMap(slice []string) map[string]struct{} {
m := map[string]struct{}{}
func sliceToMap(slice []string) (map[uint64]struct{}, error) {
m := map[uint64]struct{}{}
for _, s := range slice {
m[s] = struct{}{}
i, err := ipStringToInt(s)
if err != nil {
return m, err
}
m[i] = struct{}{}
}
return m
return m, nil
}
// Convert an IPV4 or IPV6 address string to an easily iterable uint64.
@ -220,3 +242,55 @@ func byteArrayToInt(arr []byte) uint64 {
}
return val
}
// Transforms a subnet into k8s-friendly resource name
func subnetResourceName(subnet string) string {
regex := regexp.MustCompile(`[:./]`)
return "ippool-" + regex.ReplaceAllString(subnet, "-")
}
// Persist a pool to the API server (Create or Update)
func (i *Ipam) applyIPPool(ctx context.Context, spec vinov1.IPPoolSpec) error {
logger := i.Log.WithValues("subnet", spec.Subnet)
ippool := &vinov1.IPPool{
ObjectMeta: metav1.ObjectMeta{
Namespace: i.Namespace,
Name: subnetResourceName(spec.Subnet),
},
Spec: spec,
}
existingPool := &vinov1.IPPool{}
err := i.Client.Get(ctx, client.ObjectKeyFromObject(ippool), existingPool)
if err != nil {
// Is it an unexpected error?
if !apierrors.IsNotFound(err) {
return err
}
// The error is a warning that the resource doesn't exist yet, so we should create it
logger.Info("IPAM creating IPPool")
err = i.Client.Create(ctx, ippool)
} else {
logger.Info("IPAM IPPool already exists; updating it")
ippool.ObjectMeta.ResourceVersion = existingPool.ObjectMeta.ResourceVersion
err = i.Client.Update(ctx, ippool)
}
if err != nil {
return err
}
return err
}
// Return a mapping of all allocated subnets to their IPPoolSpecs.
func (i *Ipam) getIPPools(ctx context.Context) (map[string]*vinov1.IPPoolSpec, error) {
list := &vinov1.IPPoolList{}
err := i.Client.List(ctx, list, client.InNamespace(i.Namespace))
ippools := make(map[string]*vinov1.IPPoolSpec)
if err != nil {
return map[string]*vinov1.IPPoolSpec{}, err
}
for _, ippool := range list.Items {
ippools[ippool.Spec.Subnet] = ippool.Spec.DeepCopy()
}
return ippools, nil
}

View File

@ -15,15 +15,72 @@
package ipam
import (
"context"
"math"
"testing"
vinov1 "vino/pkg/api/v1"
test "vino/pkg/test"
gomock "github.com/golang/mock/gomock"
"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/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
)
// Sets up a mock client that will serve up
func SetUpMockClient(ctx context.Context, ctrl *gomock.Controller) *test.MockClient {
m := test.NewMockClient(ctrl)
// Pre-populate IPAM with some precondition test data
preExistingIpam := vinov1.IPPoolList{
Items: []vinov1.IPPool{
{
Spec: vinov1.IPPoolSpec{
Subnet: "10.0.0.0/16",
Ranges: []vinov1.Range{
{Start: "10.0.1.0", Stop: "10.0.1.9"},
},
},
},
{
Spec: vinov1.IPPoolSpec{
Subnet: "2600:1700:b030:0000::/72",
Ranges: []vinov1.Range{
{Start: "2600:1700:b030:0000::", Stop: "2600:1700:b030:0009::"},
},
},
},
{
Spec: vinov1.IPPoolSpec{
Subnet: "192.168.0.0/1",
Ranges: []vinov1.Range{
{Start: "192.168.0.0", Stop: "192.168.0.0"},
},
AllocatedIPs: []string{"192.168.0.0"},
},
},
{
Spec: vinov1.IPPoolSpec{
Subnet: "2600:1700:b031:0000::/64",
Ranges: []vinov1.Range{
{Start: "2600:1700:b031:0000::", Stop: "2600:1700:b031:0000::"},
},
AllocatedIPs: []string{"2600:1700:b031:0000::"},
},
},
},
}
m.EXPECT().List(ctx, gomock.Any(), gomock.Any()).SetArg(1, preExistingIpam)
m.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).AnyTimes()
m.EXPECT().Create(ctx, gomock.Any(), gomock.Any()).AnyTimes()
m.EXPECT().Update(ctx, gomock.Any(), gomock.Any()).AnyTimes()
return m
}
func TestAllocateIP(t *testing.T) {
tests := []struct {
name, subnet, expectedErr string
@ -79,32 +136,21 @@ func TestAllocateIP(t *testing.T) {
},
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
ipammer := NewIpam()
m := SetUpMockClient(ctx, ctrl)
ipammer := NewIpam(log.Log, m, "vino-system")
ipammer.Log = log.Log
// Pre-populate IPAM with some precondition test data
err := ipammer.AddSubnetRange("10.0.0.0/16", vinov1.Range{Start: "10.0.1.0", Stop: "10.0.1.9"})
require.NoError(t, err)
err = ipammer.AddSubnetRange("2600:1700:b030:0000::/72",
vinov1.Range{Start: "2600:1700:b030:0000::", Stop: "2600:1700:b030:0009::"})
require.NoError(t, err)
err = ipammer.AddSubnetRange("192.168.0.0/1",
vinov1.Range{Start: "192.168.0.0", Stop: "192.168.0.0"})
require.NoError(t, err)
err = ipammer.AddSubnetRange("2600:1700:b031:0000::/64",
vinov1.Range{Start: "2600:1700:b031:0000::", Stop: "2600:1700:b031:0000::"})
require.NoError(t, err)
_, err = ipammer.AllocateIP("192.168.0.0/1", vinov1.Range{Start: "192.168.0.0", Stop: "192.168.0.0"})
require.NoError(t, err)
_, err = ipammer.AllocateIP("2600:1700:b031:0000::/64",
vinov1.Range{Start: "2600:1700:b031:0000::", Stop: "2600:1700:b031:0000::"})
require.NoError(t, err)
ip, err := ipammer.AllocateIP(tt.subnet, tt.subnetRange)
ip, err := ipammer.AllocateIP(ctx, tt.subnet, tt.subnetRange)
if tt.expectedErr != "" {
assert.Equal(t, "", ip)
require.Error(t, err)
assert.Equal(t, "", ip)
assert.Contains(t, err.Error(), tt.expectedErr)
} else {
require.NoError(t, err)
@ -180,15 +226,17 @@ func TestAddSubnetRange(t *testing.T) {
// TODO: check for partially overlapping ranges and subnets
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
ipammer := NewIpam()
m := SetUpMockClient(ctx, ctrl)
ipammer := NewIpam(log.Log, m, "vino-system")
// Pre-populate IPAM with some precondition test data
err := ipammer.AddSubnetRange("10.0.0.0/16", vinov1.Range{Start: "10.0.1.0", Stop: "10.0.1.9"})
require.NoError(t, err)
err = ipammer.AddSubnetRange(tt.subnet, tt.subnetRange)
err := ipammer.AddSubnetRange(ctx, tt.subnet, tt.subnetRange)
if tt.expectedErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedErr)
@ -264,30 +312,31 @@ func TestSliceToMap(t *testing.T) {
tests := []struct {
name string
in []string
out map[string]struct{}
out map[uint64]struct{}
}{
{
name: "empty slice",
in: []string{},
out: map[string]struct{}{},
out: map[uint64]struct{}{},
},
{
name: "one-element slice",
in: []string{"foo"},
out: map[string]struct{}{"foo": {}},
in: []string{"0.0.0.1"},
out: map[uint64]struct{}{1: {}},
},
{
name: "two-element slice",
in: []string{"foo", "bar"},
out: map[string]struct{}{"foo": {}, "bar": {}},
in: []string{"0.0.0.1", "0.0.0.2"},
out: map[uint64]struct{}{1: {}, 2: {}},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
actual := sliceToMap(tt.in)
actual, err := sliceToMap(tt.in)
assert.Equal(t, tt.out, actual)
require.NoError(t, err)
})
}
}
@ -402,3 +451,119 @@ func TestByteArrayToInt(t *testing.T) {
})
}
}
func TestSubnetResourceName(t *testing.T) {
tests := []struct {
name string
in string
out string
}{
{
name: "ipv4",
in: "192.168.0.0/24",
out: "ippool-192-168-0-0-24",
},
{
name: "ipv6",
in: "0001:0000:0000:0001::/32",
out: "ippool-0001-0000-0000-0001---32",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
actual := subnetResourceName(tt.in)
assert.Equal(t, tt.out, actual)
})
}
}
func TestApplyIPPool(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := test.NewMockClient(ctrl)
ipammer := NewIpam(log.Log, m, "vino-system")
ctx := context.Background()
spec := vinov1.IPPoolSpec{
Subnet: "192.168.0.0/24",
Ranges: []vinov1.Range{
{
Start: "192.168.1.10",
Stop: "192.168.1.20",
},
},
}
pool := vinov1.IPPool{
ObjectMeta: metav1.ObjectMeta{
Namespace: "vino-system",
Name: "ippool-192-168-0-0-24",
},
Spec: spec,
}
emptyPool := &vinov1.IPPool{}
// Test Create scenario
m = test.NewMockClient(ctrl)
ipammer.Client = m
m.EXPECT().Get(ctx, client.ObjectKeyFromObject(&pool), emptyPool).Return(
apierrors.NewNotFound(schema.GroupResource{
Group: "airship.airshipit.org", Resource: "ippools"}, "ippool-192-168-0-0-24"))
m.EXPECT().Create(ctx, &pool)
err := ipammer.applyIPPool(ctx, spec)
assert.NoError(t, err)
// Test Update scenario
existingPool := pool.DeepCopy()
existingPool.Generation = 1
m = test.NewMockClient(ctrl)
ipammer.Client = m
m.EXPECT().Get(ctx, client.ObjectKeyFromObject(&pool), emptyPool).SetArg(2, *existingPool)
m.EXPECT().Update(ctx, &pool)
err = ipammer.applyIPPool(ctx, spec)
assert.NoError(t, err)
// Test non-already-exists error scenario
m = test.NewMockClient(ctrl)
ipammer.Client = m
m.EXPECT().Get(ctx, client.ObjectKeyFromObject(&pool), emptyPool).Return(
apierrors.NewBadRequest("bad things happened"))
err = ipammer.applyIPPool(ctx, spec)
assert.Error(t, err)
}
func TestGetIPPools(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
spec := vinov1.IPPoolSpec{
Subnet: "192.168.0.0/24",
Ranges: []vinov1.Range{
{
Start: "192.168.1.10",
Stop: "192.168.1.20",
},
},
}
pool := vinov1.IPPool{
ObjectMeta: metav1.ObjectMeta{
Namespace: "vino-system",
Name: "ippool-192-168-0-0-24",
},
Spec: spec,
}
fullList := vinov1.IPPoolList{Items: []vinov1.IPPool{pool}}
expectedResult := map[string]*vinov1.IPPoolSpec{"192.168.0.0/24": &spec}
m := test.NewMockClient(ctrl)
ipammer := NewIpam(log.Log, m, "vino-system")
ipammer.Client = m
m.EXPECT().List(ctx, gomock.Any(), client.InNamespace("vino-system")).SetArg(1, fullList)
actualResult, err := ipammer.getIPPools(ctx)
assert.NoError(t, err)
assert.Equal(t, expectedResult, actualResult)
}

208
pkg/test/mock_client.go Normal file
View File

@ -0,0 +1,208 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: sigs.k8s.io/controller-runtime/pkg/client (interfaces: Client)
// Package mock_client is a generated GoMock package.
package ipam
import (
context "context"
gomock "github.com/golang/mock/gomock"
meta "k8s.io/apimachinery/pkg/api/meta"
runtime "k8s.io/apimachinery/pkg/runtime"
types "k8s.io/apimachinery/pkg/types"
reflect "reflect"
client "sigs.k8s.io/controller-runtime/pkg/client"
)
// MockClient is a mock of Client interface
type MockClient struct {
ctrl *gomock.Controller
recorder *MockClientMockRecorder
}
// MockClientMockRecorder is the mock recorder for MockClient
type MockClientMockRecorder struct {
mock *MockClient
}
// NewMockClient creates a new mock instance
func NewMockClient(ctrl *gomock.Controller) *MockClient {
mock := &MockClient{ctrl: ctrl}
mock.recorder = &MockClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockClient) EXPECT() *MockClientMockRecorder {
return m.recorder
}
// Create mocks base method
func (m *MockClient) Create(arg0 context.Context, arg1 client.Object, arg2 ...client.CreateOption) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Create", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// Create indicates an expected call of Create
func (mr *MockClientMockRecorder) Create(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockClient)(nil).Create), varargs...)
}
// Delete mocks base method
func (m *MockClient) Delete(arg0 context.Context, arg1 client.Object, arg2 ...client.DeleteOption) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Delete", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete
func (mr *MockClientMockRecorder) Delete(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClient)(nil).Delete), varargs...)
}
// DeleteAllOf mocks base method
func (m *MockClient) DeleteAllOf(arg0 context.Context, arg1 client.Object, arg2 ...client.DeleteAllOfOption) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "DeleteAllOf", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteAllOf indicates an expected call of DeleteAllOf
func (mr *MockClientMockRecorder) DeleteAllOf(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAllOf", reflect.TypeOf((*MockClient)(nil).DeleteAllOf), varargs...)
}
// Get mocks base method
func (m *MockClient) Get(arg0 context.Context, arg1 types.NamespacedName, arg2 client.Object) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// Get indicates an expected call of Get
func (mr *MockClientMockRecorder) Get(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockClient)(nil).Get), arg0, arg1, arg2)
}
// List mocks base method
func (m *MockClient) List(arg0 context.Context, arg1 client.ObjectList, arg2 ...client.ListOption) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "List", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// List indicates an expected call of List
func (mr *MockClientMockRecorder) List(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List), varargs...)
}
// Patch mocks base method
func (m *MockClient) Patch(arg0 context.Context, arg1 client.Object, arg2 client.Patch, arg3 ...client.PatchOption) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1, arg2}
for _, a := range arg3 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Patch", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// Patch indicates an expected call of Patch
func (mr *MockClientMockRecorder) Patch(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Patch", reflect.TypeOf((*MockClient)(nil).Patch), varargs...)
}
// RESTMapper mocks base method
func (m *MockClient) RESTMapper() meta.RESTMapper {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RESTMapper")
ret0, _ := ret[0].(meta.RESTMapper)
return ret0
}
// RESTMapper indicates an expected call of RESTMapper
func (mr *MockClientMockRecorder) RESTMapper() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RESTMapper", reflect.TypeOf((*MockClient)(nil).RESTMapper))
}
// Scheme mocks base method
func (m *MockClient) Scheme() *runtime.Scheme {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Scheme")
ret0, _ := ret[0].(*runtime.Scheme)
return ret0
}
// Scheme indicates an expected call of Scheme
func (mr *MockClientMockRecorder) Scheme() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Scheme", reflect.TypeOf((*MockClient)(nil).Scheme))
}
// Status mocks base method
func (m *MockClient) Status() client.StatusWriter {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Status")
ret0, _ := ret[0].(client.StatusWriter)
return ret0
}
// Status indicates an expected call of Status
func (mr *MockClientMockRecorder) Status() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockClient)(nil).Status))
}
// Update mocks base method
func (m *MockClient) Update(arg0 context.Context, arg1 client.Object, arg2 ...client.UpdateOption) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Update", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update
func (mr *MockClientMockRecorder) Update(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockClient)(nil).Update), varargs...)
}