Skip to content

Commit

Permalink
hybrid deploy
Browse files Browse the repository at this point in the history
Signed-off-by: Lyndon-Li <[email protected]>
  • Loading branch information
Lyndon-Li committed Dec 10, 2024
1 parent 0ea4eb5 commit 2ed820d
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 19 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/8504-Lyndon-Li
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix issue #8416, #8417, deploy Velero server and node-agent in linux/Windows hybrid env
7 changes: 6 additions & 1 deletion pkg/cmd/cli/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,12 @@ func (o *Options) Run(c *cobra.Command, f client.Factory) error {

if o.UseNodeAgent {
fmt.Println("Waiting for node-agent daemonset to be ready.")
if _, err = install.DaemonSetIsReady(dynamicFactory, o.Namespace); err != nil {
if _, err = install.NodeAgentIsReady(dynamicFactory, o.Namespace); err != nil {
return errors.Wrap(err, errorMsg)
}

Check warning on line 399 in pkg/cmd/cli/install/install.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/cli/install/install.go#L397-L399

Added lines #L397 - L399 were not covered by tests

fmt.Println("Waiting for node-agent-windows daemonset to be ready.")
if _, err = install.NodeAgentWindowsIsReady(dynamicFactory, o.Namespace); err != nil {

Check warning on line 402 in pkg/cmd/cli/install/install.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/cli/install/install.go#L401-L402

Added lines #L401 - L402 were not covered by tests
return errors.Wrap(err, errorMsg)
}
}
Expand Down
28 changes: 23 additions & 5 deletions pkg/cmd/cli/nodeagent/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,31 @@ func newNodeAgentServer(logger logrus.FieldLogger, factory client.Factory, confi
},
},
}
mgr, err := ctrl.NewManager(clientConfig, ctrl.Options{
Scheme: scheme,
Cache: cacheOption,
})

var mgr manager.Manager
retry := 10
for {
mgr, err = ctrl.NewManager(clientConfig, ctrl.Options{
Scheme: scheme,
Cache: cacheOption,
})
if err == nil {
break

Check warning on line 212 in pkg/cmd/cli/nodeagent/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/cli/nodeagent/server.go#L203-L212

Added lines #L203 - L212 were not covered by tests
}

retry--
if retry == 0 {
break

Check warning on line 217 in pkg/cmd/cli/nodeagent/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/cli/nodeagent/server.go#L215-L217

Added lines #L215 - L217 were not covered by tests
}

logger.WithError(err).Warn("Failed to create controller manager, need retry")

time.Sleep(time.Second)

Check warning on line 222 in pkg/cmd/cli/nodeagent/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/cli/nodeagent/server.go#L220-L222

Added lines #L220 - L222 were not covered by tests
}

if err != nil {
cancelFunc()
return nil, err
return nil, errors.Wrap(err, "error creating controller manager")

Check warning on line 227 in pkg/cmd/cli/nodeagent/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/cli/nodeagent/server.go#L227

Added line #L227 was not covered by tests
}

s := &nodeAgentServer{
Expand Down
33 changes: 25 additions & 8 deletions pkg/cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,17 +239,34 @@ func newServer(f client.Factory, config *config.Config, logger *logrus.Logger) (

ctrl.SetLogger(logrusr.New(logger))

mgr, err := ctrl.NewManager(clientConfig, ctrl.Options{
Scheme: scheme,
Cache: cache.Options{
DefaultNamespaces: map[string]cache.Config{
f.Namespace(): {},
var mgr manager.Manager
retry := 10
for {
mgr, err = ctrl.NewManager(clientConfig, ctrl.Options{
Scheme: scheme,
Cache: cache.Options{
DefaultNamespaces: map[string]cache.Config{
f.Namespace(): {},
},

Check warning on line 250 in pkg/cmd/server/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/server/server.go#L242-L250

Added lines #L242 - L250 were not covered by tests
},
},
})
})
if err == nil {
break

Check warning on line 254 in pkg/cmd/server/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/server/server.go#L252-L254

Added lines #L252 - L254 were not covered by tests
}

retry--
if retry == 0 {
break

Check warning on line 259 in pkg/cmd/server/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/server/server.go#L257-L259

Added lines #L257 - L259 were not covered by tests
}

logger.WithError(err).Warn("Failed to create controller manager, need retry")

time.Sleep(time.Second)

Check warning on line 264 in pkg/cmd/server/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/server/server.go#L262-L264

Added lines #L262 - L264 were not covered by tests
}

if err != nil {
cancelFunc()
return nil, err
return nil, errors.Wrap(err, "error creating controller manager")

Check warning on line 269 in pkg/cmd/server/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/server/server.go#L269

Added line #L269 was not covered by tests
}

credentialFileStore, err := credentials.NewNamespacedFileStore(
Expand Down
23 changes: 23 additions & 0 deletions pkg/install/daemonset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,23 @@ import (
)

func TestDaemonSet(t *testing.T) {
userID := int64(0)
boolFalse := false
boolTrue := true

ds := DaemonSet("velero")

assert.Equal(t, "node-agent", ds.Spec.Template.Spec.Containers[0].Name)
assert.Equal(t, "velero", ds.ObjectMeta.Namespace)
assert.Equal(t, "node-agent", ds.Spec.Template.ObjectMeta.Labels["name"])
assert.Equal(t, "node-agent", ds.Spec.Template.ObjectMeta.Labels["role"])
assert.Equal(t, "linux", ds.Spec.Template.Spec.NodeSelector["kubernetes.io/os"])
assert.Equal(t, "linux", string(ds.Spec.Template.Spec.OS.Name))
assert.Equal(t, corev1.PodSecurityContext{RunAsUser: &userID}, *ds.Spec.Template.Spec.SecurityContext)
assert.Equal(t, corev1.SecurityContext{Privileged: &boolFalse}, *ds.Spec.Template.Spec.Containers[0].SecurityContext)

ds = DaemonSet("velero", WithPrivilegedNodeAgent(true))
assert.Equal(t, corev1.SecurityContext{Privileged: &boolTrue}, *ds.Spec.Template.Spec.Containers[0].SecurityContext)

ds = DaemonSet("velero", WithImage("velero/velero:v0.11"))
assert.Equal(t, "velero/velero:v0.11", ds.Spec.Template.Spec.Containers[0].Image)
Expand All @@ -47,4 +60,14 @@ func TestDaemonSet(t *testing.T) {

ds = DaemonSet("velero", WithServiceAccountName("test-sa"))
assert.Equal(t, "test-sa", ds.Spec.Template.Spec.ServiceAccountName)

ds = DaemonSet("velero", WithForWinows())
assert.Equal(t, "node-agent-windows", ds.Spec.Template.Spec.Containers[0].Name)
assert.Equal(t, "velero", ds.ObjectMeta.Namespace)
assert.Equal(t, "node-agent-windows", ds.Spec.Template.ObjectMeta.Labels["name"])
assert.Equal(t, "node-agent", ds.Spec.Template.ObjectMeta.Labels["role"])
assert.Equal(t, "windows", ds.Spec.Template.Spec.NodeSelector["kubernetes.io/os"])
assert.Equal(t, "windows", string(ds.Spec.Template.Spec.OS.Name))
assert.Equal(t, (*corev1.PodSecurityContext)(nil), ds.Spec.Template.Spec.SecurityContext)
assert.Equal(t, (*corev1.SecurityContext)(nil), ds.Spec.Template.Spec.Containers[0].SecurityContext)
}
16 changes: 13 additions & 3 deletions pkg/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,19 @@ func DeploymentIsReady(factory client.DynamicFactory, namespace string) (bool, e
return isReady, err
}

// DaemonSetIsReady will poll the Kubernetes API server to ensure the node-agent daemonset is ready, i.e. that
// NodeAgentIsReady will poll the Kubernetes API server to ensure the node-agent daemonset is ready, i.e. that
// pods are scheduled and available on all of the desired nodes.
func DaemonSetIsReady(factory client.DynamicFactory, namespace string) (bool, error) {
func NodeAgentIsReady(factory client.DynamicFactory, namespace string) (bool, error) {
return daemonSetIsReady(factory, namespace, "node-agent")
}

// NodeAgentWindowsIsReady will poll the Kubernetes API server to ensure the node-agent-windows daemonset is ready, i.e. that
// pods are scheduled and available on all of the desired nodes.
func NodeAgentWindowsIsReady(factory client.DynamicFactory, namespace string) (bool, error) {
return daemonSetIsReady(factory, namespace, "node-agent-windows")
}

func daemonSetIsReady(factory client.DynamicFactory, namespace string, name string) (bool, error) {
gvk := schema.FromAPIVersionAndKind(appsv1.SchemeGroupVersion.String(), "DaemonSet")
apiResource := metav1.APIResource{
Name: "daemonsets",
Expand All @@ -225,7 +235,7 @@ func DaemonSetIsReady(factory client.DynamicFactory, namespace string) (bool, er
var readyObservations int32

err = wait.PollUntilContextTimeout(context.Background(), time.Second, time.Minute, true, func(ctx context.Context) (bool, error) {
unstructuredDaemonSet, err := c.Get("node-agent", metav1.GetOptions{})
unstructuredDaemonSet, err := c.Get(name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return false, nil
} else if err != nil {
Expand Down
25 changes: 23 additions & 2 deletions pkg/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func TestDeploymentIsReady(t *testing.T) {
assert.True(t, ready)
}

func TestDaemonSetIsReady(t *testing.T) {
func TestNodeAgentIsReady(t *testing.T) {
daemonset := &appsv1.DaemonSet{
Status: appsv1.DaemonSetStatus{
NumberAvailable: 1,
Expand All @@ -143,7 +143,28 @@ func TestDaemonSetIsReady(t *testing.T) {
factory := &test.FakeDynamicFactory{}
factory.On("ClientForGroupVersionResource", mock.Anything, mock.Anything, mock.Anything).Return(dc, nil)

ready, err := DaemonSetIsReady(factory, "velero")
ready, err := NodeAgentIsReady(factory, "velero")
require.NoError(t, err)
assert.True(t, ready)
}

func TestNodeAgentWindowsIsReady(t *testing.T) {
daemonset := &appsv1.DaemonSet{
Status: appsv1.DaemonSetStatus{
NumberAvailable: 0,
DesiredNumberScheduled: 0,
},
}
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(daemonset)
require.NoError(t, err)

dc := &test.FakeDynamicClient{}
dc.On("Get", mock.Anything, mock.Anything).Return(&unstructured.Unstructured{Object: obj}, nil)

factory := &test.FakeDynamicFactory{}
factory.On("ClientForGroupVersionResource", mock.Anything, mock.Anything, mock.Anything).Return(dc, nil)

ready, err := NodeAgentWindowsIsReady(factory, "velero")
require.NoError(t, err)
assert.True(t, ready)
}
24 changes: 24 additions & 0 deletions pkg/plugin/clientmgmt/process/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,22 @@ func TestNewRegistry(t *testing.T) {

type fakeFileInfo struct {
fs.FileInfo
name string
mode os.FileMode
}

func (f *fakeFileInfo) Mode() os.FileMode {
return f.mode
}

func (f *fakeFileInfo) Name() string {
return f.name
}

func TestExecutable(t *testing.T) {
tests := []struct {
name string
fileName string
mode uint32
expectExecutable bool
}{
Expand Down Expand Up @@ -90,11 +96,29 @@ func TestExecutable(t *testing.T) {
mode: 0777,
expectExecutable: true,
},
{
name: "windows lower case",
fileName: "test.exe",
mode: 0,
expectExecutable: true,
},
{
name: "windows upper case",
fileName: "test.EXE",
mode: 0,
expectExecutable: true,
},
{
name: "windows wrong ext",
fileName: "test.EXE1",
mode: 0,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
info := &fakeFileInfo{
name: test.fileName,
mode: os.FileMode(test.mode),
}

Expand Down

0 comments on commit 2ed820d

Please sign in to comment.