Skip to content

Commit 7df180f

Browse files
committed
Add exec package and server version denifing
1 parent 9bc8cb1 commit 7df180f

File tree

6 files changed

+238
-82
lines changed

6 files changed

+238
-82
lines changed

clientcmd/clientcmd.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package clientcmd
2+
3+
import (
4+
"io"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
"k8s.io/client-go/kubernetes/scheme"
8+
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
9+
restclient "k8s.io/client-go/rest"
10+
"k8s.io/client-go/tools/clientcmd"
11+
"k8s.io/client-go/tools/remotecommand"
12+
)
13+
14+
type Client struct {
15+
client corev1client.CoreV1Interface
16+
restconfig *restclient.Config
17+
}
18+
19+
func NewClient() (*Client, error) {
20+
// Instantiate loader for kubeconfig file.
21+
kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
22+
clientcmd.NewDefaultClientConfigLoadingRules(),
23+
&clientcmd.ConfigOverrides{},
24+
)
25+
26+
// Get a rest.Config from the kubeconfig file. This will be passed into all
27+
// the client objects we create.
28+
restconfig, err := kubeconfig.ClientConfig()
29+
if err != nil {
30+
return nil, err
31+
}
32+
33+
// Create a Kubernetes core/v1 client.
34+
cl, err := corev1client.NewForConfig(restconfig)
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
return &Client{
40+
client: cl,
41+
restconfig: restconfig,
42+
}, nil
43+
}
44+
45+
func (c *Client) Exec(pod *corev1.Pod, containerName string, command []string, stdin io.Reader, stdout, stderr io.Writer, tty bool) error {
46+
// Prepare the API URL used to execute another process within the Pod. In
47+
// this case, we'll run a remote shell.
48+
req := c.client.RESTClient().
49+
Post().
50+
Namespace(pod.Namespace).
51+
Resource("pods").
52+
Name(pod.Name).
53+
SubResource("exec").
54+
VersionedParams(&corev1.PodExecOptions{
55+
Container: containerName,
56+
Command: command,
57+
Stdin: stdin != nil,
58+
Stdout: stdout != nil,
59+
Stderr: stderr != nil,
60+
TTY: tty,
61+
}, scheme.ParameterCodec)
62+
63+
exec, err := remotecommand.NewSPDYExecutor(c.restconfig, "POST", req.URL())
64+
if err != nil {
65+
return err
66+
}
67+
68+
// Connect this process' std{in,out,err} to the remote shell process.
69+
return exec.Stream(remotecommand.StreamOptions{
70+
Stdin: stdin,
71+
Stdout: stdout,
72+
Stderr: stderr,
73+
Tty: tty,
74+
})
75+
}
76+
77+
func (c *Client) REST() restclient.Interface {
78+
return c.client.RESTClient()
79+
}

cmd/manager/main.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"os"
88
"runtime"
99

10-
"github.com/Percona-Lab/percona-server-mongodb-operator/percona-server-mongodb-operator/pkg/apis"
11-
"github.com/Percona-Lab/percona-server-mongodb-operator/percona-server-mongodb-operator/pkg/controller"
1210
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
1311
"github.com/operator-framework/operator-sdk/pkg/leader"
1412
"github.com/operator-framework/operator-sdk/pkg/ready"
@@ -18,6 +16,9 @@ import (
1816
"sigs.k8s.io/controller-runtime/pkg/manager"
1917
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
2018
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
19+
20+
"github.com/Percona-Lab/percona-server-mongodb-operator/pkg/apis"
21+
"github.com/Percona-Lab/percona-server-mongodb-operator/pkg/controller"
2122
)
2223

2324
var log = logf.Log.WithName("cmd")

pkg/apis/psmdb/v1alpha1/perconaservermongodb_types.go

-4
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,3 @@ type Expose struct {
242242
Enabled bool `json:"enabled"`
243243
ExposeType corev1.ServiceType `json:"exposeType,omitempty"`
244244
}
245-
246-
func init() {
247-
SchemeBuilder.Register(&PerconaServerMongoDB{}, &PerconaServerMongoDBList{})
248-
}

pkg/apis/psmdb/v1alpha1/register.go

+4
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ var (
1717
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
1818
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
1919
)
20+
21+
func init() {
22+
SchemeBuilder.Register(&PerconaServerMongoDB{}, &PerconaServerMongoDBList{})
23+
}

pkg/controller/perconaservermongodb/perconaservermongodb_controller.go

+53-76
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,49 @@ package perconaservermongodb
22

33
import (
44
"context"
5+
"fmt"
56

6-
psmdbv1alpha1 "github.com/Percona-Lab/percona-server-mongodb-operator/pkg/apis/psmdb/v1alpha1"
7-
corev1 "k8s.io/api/core/v1"
87
"k8s.io/apimachinery/pkg/api/errors"
9-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
108
"k8s.io/apimachinery/pkg/runtime"
11-
"k8s.io/apimachinery/pkg/types"
129
"sigs.k8s.io/controller-runtime/pkg/client"
1310
"sigs.k8s.io/controller-runtime/pkg/controller"
14-
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1511
"sigs.k8s.io/controller-runtime/pkg/handler"
1612
"sigs.k8s.io/controller-runtime/pkg/manager"
1713
"sigs.k8s.io/controller-runtime/pkg/reconcile"
1814
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
1915
"sigs.k8s.io/controller-runtime/pkg/source"
20-
)
2116

22-
var log = logf.Log.WithName("controller_perconaservermongodb")
17+
api "github.com/Percona-Lab/percona-server-mongodb-operator/pkg/apis/psmdb/v1alpha1"
18+
"github.com/Percona-Lab/percona-server-mongodb-operator/version"
19+
)
2320

24-
/**
25-
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
26-
* business logic. Delete these comments after modifying this file.*
27-
*/
21+
var log = logf.Log.WithName("controller_psmdb")
2822

2923
// Add creates a new PerconaServerMongoDB Controller and adds it to the Manager. The Manager will set fields on the Controller
3024
// and Start it when the Manager is Started.
3125
func Add(mgr manager.Manager) error {
32-
return add(mgr, newReconciler(mgr))
26+
r, err := newReconciler(mgr)
27+
if err != nil {
28+
return err
29+
}
30+
31+
return add(mgr, r)
3332
}
3433

3534
// newReconciler returns a new reconcile.Reconciler
36-
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
37-
return &ReconcilePerconaServerMongoDB{client: mgr.GetClient(), scheme: mgr.GetScheme()}
35+
func newReconciler(mgr manager.Manager) (reconcile.Reconciler, error) {
36+
sv, err := version.Server()
37+
if err != nil {
38+
return nil, fmt.Errorf("get server version: %v", err)
39+
}
40+
41+
log.Info("server version", "platform", sv.Platform, "version", sv.Info)
42+
43+
return &ReconcilePerconaServerMongoDB{
44+
client: mgr.GetClient(),
45+
scheme: mgr.GetScheme(),
46+
serverVersion: sv,
47+
}, nil
3848
}
3949

4050
// add adds a new Controller to mgr with r as the reconcile.Reconciler
@@ -46,17 +56,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
4656
}
4757

4858
// Watch for changes to primary resource PerconaServerMongoDB
49-
err = c.Watch(&source.Kind{Type: &psmdbv1alpha1.PerconaServerMongoDB{}}, &handler.EnqueueRequestForObject{})
50-
if err != nil {
51-
return err
52-
}
53-
54-
// TODO(user): Modify this to be the types you create that are owned by the primary resource
55-
// Watch for changes to secondary resource Pods and requeue the owner PerconaServerMongoDB
56-
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
57-
IsController: true,
58-
OwnerType: &psmdbv1alpha1.PerconaServerMongoDB{},
59-
})
59+
err = c.Watch(&source.Kind{Type: &api.PerconaServerMongoDB{}}, &handler.EnqueueRequestForObject{})
6060
if err != nil {
6161
return err
6262
}
@@ -72,12 +72,12 @@ type ReconcilePerconaServerMongoDB struct {
7272
// that reads objects from the cache and writes to the apiserver
7373
client client.Client
7474
scheme *runtime.Scheme
75+
76+
serverVersion *version.ServerVersion
7577
}
7678

7779
// Reconcile reads that state of the cluster for a PerconaServerMongoDB object and makes changes based on the state read
7880
// and what is in the PerconaServerMongoDB.Spec
79-
// TODO(user): Modify this Reconcile function to implement your Controller logic. This example creates
80-
// a Pod as an example
8181
// Note:
8282
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
8383
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
@@ -86,8 +86,8 @@ func (r *ReconcilePerconaServerMongoDB) Reconcile(request reconcile.Request) (re
8686
reqLogger.Info("Reconciling PerconaServerMongoDB")
8787

8888
// Fetch the PerconaServerMongoDB instance
89-
instance := &psmdbv1alpha1.PerconaServerMongoDB{}
90-
err := r.client.Get(context.TODO(), request.NamespacedName, instance)
89+
cr := &api.PerconaServerMongoDB{}
90+
err := r.client.Get(context.TODO(), request.NamespacedName, cr)
9191
if err != nil {
9292
if errors.IsNotFound(err) {
9393
// Request object not found, could have been deleted after reconcile request.
@@ -99,54 +99,31 @@ func (r *ReconcilePerconaServerMongoDB) Reconcile(request reconcile.Request) (re
9999
return reconcile.Result{}, err
100100
}
101101

102-
// Define a new Pod object
103-
pod := newPodForCR(instance)
104-
105-
// Set PerconaServerMongoDB instance as the owner and controller
106-
if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil {
107-
return reconcile.Result{}, err
108-
}
109-
110-
// Check if this Pod already exists
111-
found := &corev1.Pod{}
112-
err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found)
113-
if err != nil && errors.IsNotFound(err) {
114-
reqLogger.Info("Creating a new Pod", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name)
115-
err = r.client.Create(context.TODO(), pod)
116-
if err != nil {
117-
return reconcile.Result{}, err
118-
}
119-
120-
// Pod created successfully - don't requeue
121-
return reconcile.Result{}, nil
122-
} else if err != nil {
123-
return reconcile.Result{}, err
124-
}
102+
// // Define a new Pod object
103+
// pod := newPodForCR(instance)
104+
105+
// // Set PerconaServerMongoDB instance as the owner and controller
106+
// if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil {
107+
// return reconcile.Result{}, err
108+
// }
109+
110+
// // Check if this Pod already exists
111+
// found := &corev1.Pod{}
112+
// err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found)
113+
// if err != nil && errors.IsNotFound(err) {
114+
// reqLogger.Info("Creating a new Pod", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name)
115+
// err = r.client.Create(context.TODO(), pod)
116+
// if err != nil {
117+
// return reconcile.Result{}, err
118+
// }
119+
120+
// // Pod created successfully - don't requeue
121+
// return reconcile.Result{}, nil
122+
// } else if err != nil {
123+
// return reconcile.Result{}, err
124+
// }
125125

126126
// Pod already exists - don't requeue
127-
reqLogger.Info("Skip reconcile: Pod already exists", "Pod.Namespace", found.Namespace, "Pod.Name", found.Name)
127+
// reqLogger.Info("Skip reconcile: Pod already exists", "Pod.Namespace", found.Namespace, "Pod.Name", found.Name)
128128
return reconcile.Result{}, nil
129129
}
130-
131-
// newPodForCR returns a busybox pod with the same name/namespace as the cr
132-
func newPodForCR(cr *psmdbv1alpha1.PerconaServerMongoDB) *corev1.Pod {
133-
labels := map[string]string{
134-
"app": cr.Name,
135-
}
136-
return &corev1.Pod{
137-
ObjectMeta: metav1.ObjectMeta{
138-
Name: cr.Name + "-pod",
139-
Namespace: cr.Namespace,
140-
Labels: labels,
141-
},
142-
Spec: corev1.PodSpec{
143-
Containers: []corev1.Container{
144-
{
145-
Name: "busybox",
146-
Image: "busybox",
147-
Command: []string{"sleep", "3600"},
148-
},
149-
},
150-
},
151-
}
152-
}

0 commit comments

Comments
 (0)