Merge "Removes BMH specific logic in the airshipctl move command. Also removes pkg dependencies that were introduced by the BMH logic."
This commit is contained in:
commit
8c180daf4e
15
go.mod
15
go.mod
@ -3,10 +3,16 @@ module opendev.org/airship/airshipctl
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Azure/go-autorest/autorest v0.11.7 // indirect
|
||||
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.0.4
|
||||
github.com/containerd/containerd v1.4.1 // indirect
|
||||
github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
@ -16,12 +22,12 @@ require (
|
||||
github.com/gorilla/mux v1.7.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
|
||||
github.com/huandu/xstrings v1.3.1 // indirect
|
||||
github.com/metal3-io/baremetal-operator v0.0.0-20200501205115-2c0dc9997bfa
|
||||
github.com/onsi/gomega v1.9.0
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb // indirect
|
||||
k8s.io/api v0.17.4
|
||||
k8s.io/apiextensions-apiserver v0.17.4
|
||||
k8s.io/apimachinery v0.17.4
|
||||
@ -37,10 +43,7 @@ require (
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
// Required by baremetal-operator:
|
||||
replace (
|
||||
github.com/Azure/go-autorest => github.com/Azure/go-autorest v13.3.2+incompatible // Required by OLM
|
||||
github.com/russross/blackfriday => github.com/russross/blackfriday v1.5.2
|
||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20191114101535-6c5935290e33
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd
|
||||
sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.4.1
|
||||
|
@ -15,46 +15,21 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/log"
|
||||
|
||||
bmoapis "github.com/metal3-io/baremetal-operator/pkg/apis"
|
||||
bmh "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
clusterctlclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client"
|
||||
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func init() {
|
||||
//nolint:errcheck
|
||||
bmoapis.AddToScheme(cluster.Scheme)
|
||||
}
|
||||
|
||||
// Move implements interface to Clusterctl
|
||||
func (c *Client) Move(fromKubeconfigPath, fromKubeconfigContext,
|
||||
toKubeconfigPath, toKubeconfigContext, namespace string) error {
|
||||
ctx := context.TODO()
|
||||
var err error
|
||||
// ephemeral cluster client
|
||||
pFrom := cluster.New(cluster.Kubeconfig{
|
||||
Path: fromKubeconfigPath,
|
||||
Context: fromKubeconfigContext}, nil).Proxy()
|
||||
cFrom, err := pFrom.NewClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create ephemeral cluster client")
|
||||
}
|
||||
// target cluster client
|
||||
pTo := cluster.New(cluster.Kubeconfig{
|
||||
Path: toKubeconfigPath,
|
||||
Context: toKubeconfigContext}, nil).Proxy()
|
||||
cTo, err := pTo.NewClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create target cluster client")
|
||||
}
|
||||
|
||||
// If namespace is empty, try to detect it.
|
||||
if namespace == "" {
|
||||
var currentNamespace string
|
||||
@ -64,11 +39,6 @@ func (c *Client) Move(fromKubeconfigPath, fromKubeconfigContext,
|
||||
}
|
||||
namespace = currentNamespace
|
||||
}
|
||||
// Pause
|
||||
err = pauseUnpauseBMHs(ctx, cFrom, namespace, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to pause BareMetalHost objects")
|
||||
}
|
||||
|
||||
// clusterctl move
|
||||
c.moveOptions = clusterctlclient.MoveOptions{
|
||||
@ -80,90 +50,5 @@ func (c *Client) Move(fromKubeconfigPath, fromKubeconfigContext,
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error during clusterctl move")
|
||||
}
|
||||
// Update BMH Status
|
||||
err = copyBMHStatus(ctx, cFrom, cTo, namespace)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy BareMetalHost Status")
|
||||
}
|
||||
// Unpause
|
||||
err = pauseUnpauseBMHs(ctx, cFrom, namespace, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to unpause BareMetalHost objects")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// copyBMHStatus will copy the BareMetalHost Status field from a specific
|
||||
// cluser to a target cluster.
|
||||
func copyBMHStatus(ctx context.Context, cFrom client.Client, cTo client.Client, namespace string) error {
|
||||
fromHosts, err := getBMHs(ctx, cFrom, namespace)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list BareMetalHost objects")
|
||||
}
|
||||
toHosts, err := getBMHs(ctx, cTo, namespace)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list BMH objects")
|
||||
}
|
||||
// Copy the Status field from old BMH to new BMH
|
||||
log.Debugf("Copying BareMetalHost status to target cluster")
|
||||
for i := range toHosts.Items {
|
||||
var found bool
|
||||
t := metav1.Now()
|
||||
for _, fromHost := range fromHosts.Items {
|
||||
if fromHost.Name == toHosts.Items[i].Name {
|
||||
toHosts.Items[i].Status = fromHost.Status
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return errors.Errorf("BMH with the same name %s/%s not found in the source cluster",
|
||||
toHosts.Items[i].Name, namespace)
|
||||
}
|
||||
toHosts.Items[i].Status.LastUpdated = &t
|
||||
err = cTo.Status().Update(ctx, &toHosts.Items[i])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to update BareMetalHost status")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pauseUnpauseBMHs will add/remove the pause annotation from the
|
||||
// BareMetalHost objects.
|
||||
func pauseUnpauseBMHs(ctx context.Context, crClient client.Client, namespace string, pause bool) error {
|
||||
hosts, err := getBMHs(ctx, crClient, namespace)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list BMH objects")
|
||||
}
|
||||
for i := range hosts.Items {
|
||||
annotations := hosts.Items[i].GetAnnotations()
|
||||
if annotations == nil {
|
||||
hosts.Items[i].Annotations = map[string]string{}
|
||||
}
|
||||
if pause {
|
||||
log.Debugf("Pausing BareMetalHost object %s/%s", hosts.Items[i].Name, namespace)
|
||||
hosts.Items[i].Annotations[bmh.PausedAnnotation] = "true"
|
||||
} else {
|
||||
log.Debugf("Unpausing BareMetalHost object %s/%s", hosts.Items[i].Name, namespace)
|
||||
delete(hosts.Items[i].Annotations, bmh.PausedAnnotation)
|
||||
}
|
||||
if err := crClient.Update(ctx, &hosts.Items[i]); err != nil {
|
||||
return errors.Wrapf(err, "error updating BareMetalHost %q %s/%s",
|
||||
hosts.Items[i].GroupVersionKind(), hosts.Items[i].GetNamespace(), hosts.Items[i].GetName())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getBMHs will return all BareMetalHost objects in the specified namespace.
|
||||
// It also checks to see if the BareMetalHost resource is installed, if not,
|
||||
// it will return false.
|
||||
func getBMHs(ctx context.Context, crClient client.Client, namespace string) (bmh.BareMetalHostList, error) {
|
||||
hosts := bmh.BareMetalHostList{}
|
||||
opts := &client.ListOptions{
|
||||
Namespace: namespace,
|
||||
}
|
||||
err := crClient.List(ctx, &hosts, opts)
|
||||
return hosts, err
|
||||
}
|
||||
|
@ -1,344 +0,0 @@
|
||||
/*
|
||||
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
|
||||
|
||||
https://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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
bmoapis "github.com/metal3-io/baremetal-operator/pkg/apis"
|
||||
bmh "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
)
|
||||
|
||||
var bmh1 = &bmh.BareMetalHost{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "metal3.io/v1alpha1",
|
||||
Kind: "BareMetalHost",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bmh1",
|
||||
Namespace: "ns1",
|
||||
},
|
||||
Spec: bmh.BareMetalHostSpec{
|
||||
Online: false,
|
||||
BootMACAddress: "00:2e:30:d7:11:19",
|
||||
},
|
||||
Status: bmh.BareMetalHostStatus{
|
||||
HardwareProfile: "bmh1-hw-profile",
|
||||
},
|
||||
}
|
||||
|
||||
var bmh2 = &bmh.BareMetalHost{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "metal3.io/v1alpha1",
|
||||
Kind: "BareMetalHost",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bmh2",
|
||||
Namespace: "ns1",
|
||||
},
|
||||
Spec: bmh.BareMetalHostSpec{
|
||||
Online: false,
|
||||
BootMACAddress: "01:23:45:67:89:ab",
|
||||
},
|
||||
Status: bmh.BareMetalHostStatus{
|
||||
HardwareProfile: "bmh2-hw-profile",
|
||||
},
|
||||
}
|
||||
|
||||
func newClientWithBMHObject() client.Client {
|
||||
scheme := runtime.NewScheme()
|
||||
//nolint:errcheck
|
||||
bmoapis.AddToScheme(scheme)
|
||||
return fake.NewFakeClientWithScheme(scheme, bmh1)
|
||||
}
|
||||
|
||||
func newClientWithTwoBMHObjects() client.Client {
|
||||
scheme := runtime.NewScheme()
|
||||
//nolint:errcheck
|
||||
bmoapis.AddToScheme(scheme)
|
||||
return fake.NewFakeClientWithScheme(scheme, bmh1, bmh2)
|
||||
}
|
||||
|
||||
func newClientWithNoBMHObject() client.Client {
|
||||
scheme := runtime.NewScheme()
|
||||
//nolint:errcheck
|
||||
bmoapis.AddToScheme(scheme)
|
||||
return fake.NewFakeClientWithScheme(scheme)
|
||||
}
|
||||
|
||||
func Test_move_getBMHs(t *testing.T) {
|
||||
type args struct {
|
||||
c client.Client
|
||||
namespace string
|
||||
}
|
||||
type want struct {
|
||||
bmhList bmh.BareMetalHostList
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "returns a BareMetalHost object",
|
||||
args: args{
|
||||
c: newClientWithBMHObject(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: false,
|
||||
want: want{
|
||||
bmhList: bmh.BareMetalHostList{
|
||||
Items: []bmh.BareMetalHost{*bmh1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "returns multiple BareMetalHost object",
|
||||
args: args{
|
||||
c: newClientWithTwoBMHObjects(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: false,
|
||||
want: want{
|
||||
bmhList: bmh.BareMetalHostList{
|
||||
Items: []bmh.BareMetalHost{*bmh1, *bmh2},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "returns an empty list of BareMetalHost objects",
|
||||
args: args{
|
||||
c: newClientWithNoBMHObject(),
|
||||
namespace: "ns2",
|
||||
},
|
||||
wantErr: false,
|
||||
want: want{
|
||||
bmhList: bmh.BareMetalHostList{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
bmhList, err := getBMHs(context.TODO(), tt.args.c, tt.args.namespace)
|
||||
if tt.wantErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(len(bmhList.Items)).To(BeEquivalentTo(len(tt.want.bmhList.Items)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_move_pauseUnpauseBMHs(t *testing.T) {
|
||||
type args struct {
|
||||
c client.Client
|
||||
namespace string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "pause and unpause a single BareMetalHost object",
|
||||
args: args{
|
||||
c: newClientWithBMHObject(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "pause and unpause multiple BareMetalHost objects",
|
||||
args: args{
|
||||
c: newClientWithTwoBMHObjects(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "pause and unpause should do nothing when there is no BareMetalHost object present",
|
||||
args: args{
|
||||
c: newClientWithNoBMHObject(),
|
||||
namespace: "ns2",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
err := pauseUnpauseBMHs(context.TODO(), tt.args.c, tt.args.namespace, true)
|
||||
if tt.wantErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
bmhList, err := getBMHs(context.TODO(), tt.args.c, tt.args.namespace)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
for _, host := range bmhList.Items {
|
||||
g.Expect(host.Annotations[bmh.PausedAnnotation]).To(Equal("true"))
|
||||
}
|
||||
err = pauseUnpauseBMHs(context.TODO(), tt.args.c, tt.args.namespace, false)
|
||||
if tt.wantErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
bmhList, err = getBMHs(context.TODO(), tt.args.c, tt.args.namespace)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
for _, host := range bmhList.Items {
|
||||
_, present := host.Annotations[bmh.PausedAnnotation]
|
||||
g.Expect(present).To(Equal(false))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var bmh1NoStatus = &bmh.BareMetalHost{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "metal3.io/v1alpha1",
|
||||
Kind: "BareMetalHost",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bmh1",
|
||||
Namespace: "ns1",
|
||||
},
|
||||
Spec: bmh.BareMetalHostSpec{
|
||||
Online: false,
|
||||
BootMACAddress: "00:2e:30:d7:11:19",
|
||||
},
|
||||
}
|
||||
|
||||
var bmh2NoStatus = &bmh.BareMetalHost{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "metal3.io/v1alpha1",
|
||||
Kind: "BareMetalHost",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bmh2",
|
||||
Namespace: "ns1",
|
||||
},
|
||||
Spec: bmh.BareMetalHostSpec{
|
||||
Online: false,
|
||||
BootMACAddress: "01:23:45:67:89:ab",
|
||||
},
|
||||
}
|
||||
|
||||
func newClientFromCluster() client.Client {
|
||||
scheme := runtime.NewScheme()
|
||||
//nolint:errcheck
|
||||
bmoapis.AddToScheme(scheme)
|
||||
return fake.NewFakeClientWithScheme(scheme, bmh1, bmh2)
|
||||
}
|
||||
|
||||
func newClientToCluster() client.Client {
|
||||
scheme := runtime.NewScheme()
|
||||
//nolint:errcheck
|
||||
bmoapis.AddToScheme(scheme)
|
||||
return fake.NewFakeClientWithScheme(scheme, bmh1NoStatus, bmh2NoStatus)
|
||||
}
|
||||
|
||||
func Test_move_copyBMHStatus(t *testing.T) {
|
||||
type args struct {
|
||||
cFrom client.Client
|
||||
cTo client.Client
|
||||
namespace string
|
||||
}
|
||||
type want struct {
|
||||
bmhList bmh.BareMetalHostList
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "copies the status field of multiple BareMetalHost objects",
|
||||
args: args{
|
||||
cFrom: newClientFromCluster(),
|
||||
cTo: newClientToCluster(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: false,
|
||||
want: want{
|
||||
bmhList: bmh.BareMetalHostList{
|
||||
Items: []bmh.BareMetalHost{*bmh1, *bmh2},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no copy occurs b/c no BareMetalHost objects are present",
|
||||
args: args{
|
||||
cFrom: newClientWithNoBMHObject(),
|
||||
cTo: newClientWithNoBMHObject(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: false,
|
||||
want: want{
|
||||
bmhList: bmh.BareMetalHostList{
|
||||
Items: []bmh.BareMetalHost{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error should occur b/c BareMetalHost does not exist in the source cluster",
|
||||
args: args{
|
||||
cFrom: newClientWithNoBMHObject(),
|
||||
cTo: newClientToCluster(),
|
||||
namespace: "ns1",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
err := copyBMHStatus(context.TODO(), tt.args.cFrom, tt.args.cTo, tt.args.namespace)
|
||||
if tt.wantErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
bmhList, err := getBMHs(context.TODO(), tt.args.cTo, tt.args.namespace)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
NEXTHOST:
|
||||
for _, host := range bmhList.Items {
|
||||
for _, wantHost := range tt.want.bmhList.Items {
|
||||
if host.Name == wantHost.Name {
|
||||
g.Expect(host.Status.HardwareProfile).To(Equal(wantHost.Status.HardwareProfile))
|
||||
continue NEXTHOST
|
||||
}
|
||||
}
|
||||
t.Errorf("unexpected host %s", host.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user