Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated documentation to adapt to new gRPC services #221

Merged
merged 5 commits into from
Feb 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 69 additions & 23 deletions docs/development/new_cp_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,33 @@ Steps to be followed while implementing a new (hyperscale) provider are mentione

### Setting up your repository

1. Fork [this repository](https://github.com/gardener/machine-controller-manager-provider-sampleprovider) on your github.
1. Rename the repository from `machine-controller-manager-provider-sampleprovider` to `machine-controller-manager-provider-{provider-name}` by updating the same in your github repository settings.
1. Create directories as required and nagivate into this path. {your-github-username} could also be {github-project}.
1. Create a new empty repository named `machine-controller-manager-provider-{provider-name}` on github. Do not initialize this repository with a README.
1. Copy the remote repository `URL` (HTTPS/SSH) to this repository which is displayed once you create this repository.
1. Now on your local system, create directories as required. {your-github-username} given below could also be {github-project} depending on where you have created the new repository.
```bash
mkdir -p $GOPATH/src/github.com/{your-github-username}
```
1. Navigate to this created directory.
```bash
cd $GOPATH/src/github.com/{your-github-username}
```
1. Clone this newly forked repository.
1. Clone [this repository](https://github.com/gardener/machine-controller-manager-provider-sampleprovider) on your local machine.
```bash
git clone [email protected]:gardener/machine-controller-manager-provider-sampleprovider.git
```
1. Rename the directory from `machine-controller-manager-provider-sampleprovider` to `machine-controller-manager-provider-{provider-name}`.
```bash
git clone https://github.com/{your-github-username}/machine-controller-manager-provider-{provider-name}
mv machine-controller-manager-provider-sampleprovider machine-controller-manager-provider-{provider-name}
```
1. Navigate into the newly created repository.
1. Navigate into the newly created directory.
```bash
cd machine-controller-manager-provider-{provider-name}
```
1. Rename github project from `gardener` to `{github-org}` or `{your-github-username}` where ever you have forked the repository above. Use the hack script given below to do the same.
1. Update the remote `origin` URL to the newly created repository's URL you had copied above.
```bash
git remote set-url origin [email protected]:{your-github-username}/machine-controller-manager-provider-{provider-name}.git
```
1. Rename github project from `gardener` to `{github-org/your-github-username}` where ever you have cloned the repository above. Use the hack script given below to do the same.
```bash
make rename-project PROJECT_NAME={github-org/your-github-username}
eg:
Expand All @@ -36,35 +47,70 @@ Steps to be followed while implementing a new (hyperscale) provider are mentione
1. Now commit your changes and push it upstream.
```bash
git add -A
git commit
git commit -m "Renamed SampleProvider"
git push origin master
```

### Code changes required

1. Update the `pkg/{provider-name}/apis/provider-spec.go` specification file to reflect the structure of the objects exchanged between the machine-controller-manager and the driver. It typically contains the machine details and secrets (if required). Follow the sample spec provided already in the file. A sample provider specification can be found [here](https://github.com/prashanth26/machine-controller-manager-provider-gcp/blob/master/pkg/gcp/apis/provider-spec.go).
```bash
vim pkg/{provider-name}/apis/provider-spec.go
```
1. Fill in the create/list/delete methods `pkg/{provider-name}/machineserver.go` to create/list/delete VMs on your cloud provider. A sample provider implementation for these methods can be found [here](https://github.com/prashanth26/machine-controller-manager-provider-gcp/blob/master/pkg/gcp/machineserver.go).
```bash
vim pkg/{provider-name}/machineserver.go
```
1. Update the `pkg/{provider-name}/apis/provider-spec.go` specification file to reflect the structure of the objects exchanged between the machine-controller-manager (AKA cmi-client) and the driver (AKA cmi-server). It typically contains the machine details and secrets (if required). Follow the sample spec provided already in the file. A sample provider specification can be found [here](https://github.com/prashanth26/machine-controller-manager-provider-gcp/blob/master/pkg/gcp/apis/provider-spec.go).
1. Fill in the methods described at `pkg/{provider-name}/machineserver.go` to manage VMs on your cloud provider.
- Fill in the required methods CREATE/GET/DELETE and LIST methods.
- The request and response parameters for each of the methods to be implemented are well documented as comments and sample codes at `pkg/{provider-name}/machineserver.go`.
- Optional methods like SHUTDOWN are optional as implicit, however we strongly recommend you to implement them as well.
- A sample provider implementation for these methods can be found [here](https://github.com/prashanth26/machine-controller-manager-provider-gcp/blob/master/pkg/gcp/machineserver.go).
1. Perform validation of APIs that you have described and make it a part of your methods as required.
1. Write unit tests to make it work with your implementation by running `make test`.
1. Re-generate the vendors, to update any new vendors imported.
```bash
make revendor
```
1. Update the sample YAML files on `kubernetes/` directory to provide sample files through which the working of the cmi-server can be tested.
1. Update `README.md` to reflect any additional changes

### Testing your code changes

Make sure `$KUBECONFIG` points to the cluster where you wish to manage machines. `$NAMESPACE` represents the namespaces where MCM is looking for machine objects.

1. Run the provider driver
```bash
go run app/controller/main.go --endpoint=tcp://127.0.0.1:8080
```
1. Run the machine-controller-manager in the `cmi-client` branch
1. On the first terminal,
- Run the cmi-server (driver) using the command below.
```bash
go run app/controller/cmi-server.go --endpoint=tcp://127.0.0.1:8080
```
1. On the second terminal,
- Clone the [latest MCM code](https://github.com/gardener/machine-controller-manager/tree/cmi-client) and switch to the `cmi-client` branch.
- Deploy the required CRDs from the machine-controller-manager repo,
```bash
kubectl apply -f kubernetes/crds.yaml
```
- Run the machine-controller-manager in the `cmi-client` branch
```bash
go run cmd/machine-controller-manager/controller_manager.go --control-kubeconfig=$KUBECONFIG --target-kubeconfig=$KUBECONFIG --namespace=$NAMESPACE
```
1. On the third terminal,
- Fill in the object files given below and deploy them as described below.
- Deploy the `machine-class`
```bash
kubectl apply -f kubernetes/machine-class.yaml
```
- Deploy the `kubernetes secret` if required.
```bash
kubectl apply -f kubernetes/secret.yaml
```
- Deploy the `machine` object and make sure it joins the cluster successfully.
```bash
kubectl apply -f kubernetes/machine.yaml
```
- Once machine joins, you can test by deploying a machine-deployment.
- Deploy the `machine-deployment` object and make sure it joins the cluster successfully.
```bash
kubectl apply -f kubernetes/machine-deployment.yaml

### Releasing your docker image

1. Make sure you have logged into gcloud/docker using the CLI.
1. To release your docker image, run the following.
```bash
go run cmd/machine-controller-manager/controller_manager.go --control-kubeconfig=$KUBECONFIG --target-kubeconfig=$KUBECONFIG --namespace=$NAMESPACE
make release IMAGE_REPOSITORY=<link-to-image-repo>
```
1. Create machineClass, secrets, machines and machinedeployment
1. A sample kubernetes deploy file can be found at `kubernetes/deployment.yaml`. Modify the same to deploy your cmi-server.
39 changes: 30 additions & 9 deletions pkg/controller/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ import (
"fmt"
"time"

"google.golang.org/grpc/codes"

"github.com/golang/glog"
"google.golang.org/grpc/status"

"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/util/sets"
Expand Down Expand Up @@ -145,7 +148,7 @@ func (c *controller) reconcileClusterMachine(machine *v1alpha1.Machine) error {
//driver := driver.NewDriver(machine.Spec.ProviderID, secretRef, machine.Spec.Class.Kind, //MachineClass, machine.Name)

// TODO: Make cloud-provider configurable via machine.spec.provider or machineclass.provider
driver := driver.NewCmiDriverClient(machine.Spec.ProviderID, "AWS", secretRef, MachineClass, machine.Name)
driver := driver.NewCMIDriverClient(machine.Spec.ProviderID, "AWS", secretRef, MachineClass, machine.Name)

actualProviderID, err := machine.Spec.ProviderID, nil
if err != nil {
Expand Down Expand Up @@ -313,7 +316,7 @@ func (c *controller) updateMachineState(machine *v1alpha1.Machine) (*v1alpha1.Ma
Machine operations - Create, Update, Delete
*/

func (c *controller) machineCreate(machine *v1alpha1.Machine, driver driver.CmiDriverClient) error {
func (c *controller) machineCreate(machine *v1alpha1.Machine, driver driver.CMIDriverClient) error {
glog.V(2).Infof("Creating machine %s, please wait!", machine.Name)

actualProviderID, nodeName, err := driver.CreateMachine()
Expand Down Expand Up @@ -413,15 +416,17 @@ func (c *controller) machineUpdate(machine *v1alpha1.Machine, actualProviderID s
return nil
}

func (c *controller) machineDelete(machine *v1alpha1.Machine, driver driver.CmiDriverClient) error {
func (c *controller) machineDelete(machine *v1alpha1.Machine, driver driver.CMIDriverClient) error {
var err error

// If Finalizers are present
if finalizers := sets.NewString(machine.Finalizers...); finalizers.Has(DeleteFinalizerName) {
glog.V(2).Infof("Deleting Machine %s", machine.Name)

// If machine was created on the cloud provider
machineID, _ := driver.GetExisting()
// Getting the machine-ID on the cloud provider
machineID := driver.MachineID

// If machine status has not been set to terminating
if machine.Status.CurrentStatus.Phase != v1alpha1.MachineTerminating {
lastOperation := v1alpha1.LastOperation{
Description: "Deleting machine from cloud provider",
Expand All @@ -446,6 +451,7 @@ func (c *controller) machineDelete(machine *v1alpha1.Machine, driver driver.CmiD
}
}

// If machine is created on the cloud provider
if machineID != "" {
timeOutDuration := c.safetyOptions.MachineDrainTimeout.Duration
// Timeout value obtained by subtracting last operation with expected time out period
Expand Down Expand Up @@ -481,12 +487,27 @@ func (c *controller) machineDelete(machine *v1alpha1.Machine, driver driver.CmiD
c.updateMachineStatus(machine, lastOperation, machine.Status.CurrentStatus)

// Machine still tries to terminate after drain failure
glog.Warningf("Drain failed for machine %s - \nBuf:%v \nErrBuf:%v \nErr-Message:%v", machine.Name, buf, errBuf, err)
glog.Warningf("Drain failed for machine %q - \nBuf:%v \nErrBuf:%v \nErr-Message:%v", machine.Name, buf, errBuf, err)
return err
}
glog.V(2).Infof("Drain successful for machine %s - %v %v", machine.Name, buf, errBuf)
glog.V(2).Infof("Drain successful for machine %q", machine.Name)
}

// Check for existance of machine at cloud provider
_, err := driver.GetMachine(machineID)
if err == nil || status.Code(err) == codes.Unimplemented {
// Either there is no err
// or the GetMachine is not implemented
// then continue

err = driver.ShutDownMachine(machineID)
if err == nil || status.Code(err) == codes.Unimplemented {
// Either there is no err
// or the ShutDownMachine is not implemented
// then continue
err = driver.DeleteMachine(machineID)
}
}
err = driver.DeleteMachine()
}

if err != nil {
Expand Down
29 changes: 14 additions & 15 deletions pkg/controller/machine_safety.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,17 +430,18 @@ func (c *controller) checkMachineClass(
}

// Dummy driver object being created to invoke GetVMs
dvr := driver.NewCmiDriverClient(
dvr := driver.NewCMIDriverClient(
"",
classKind,
secret,
machineClass,
"",
)

listOfVMs, err := dvr.GetVMs("")
listOfVMs, err := dvr.ListMachines()
if err != nil {
glog.Warningf("Failed to list VMs at provider. Err - %s", err)
glog.Warningf("Orphan VM handler is not running. Failed to list VMs at provider. Err - %s", err)
return
}

// Making sure that its not a VM just being created, machine object not yet updated at API server
Expand Down Expand Up @@ -469,16 +470,14 @@ func (c *controller) checkMachineClass(

// Re-check VM object existence
// before deleting orphan VM
result, _ := dvr.GetVMs(machineID)
for reMachineID := range result {
if reMachineID == machineID {
// Get latest version of machine object and verfiy again
machine, err := c.controlMachineClient.Machines(c.namespace).Get(machineName, metav1.GetOptions{})
if (err != nil && apierrors.IsNotFound(err)) || machine.Spec.ProviderID != machineID {
vm := make(map[string]string)
vm[machineID] = machineName
c.deleteOrphanVM(vm, secret, classKind, machineClass)
}
exists, _ := dvr.GetMachine(machineID)
if exists {
// Get latest version of machine object and verfiy again
machine, err := c.controlMachineClient.Machines(c.namespace).Get(machineName, metav1.GetOptions{})
if (err != nil && apierrors.IsNotFound(err)) || machine.Spec.ProviderID != machineID {
vm := make(map[string]string)
vm[machineID] = machineName
c.deleteOrphanVM(vm, secret, classKind, machineClass)
}
}

Expand Down Expand Up @@ -559,15 +558,15 @@ func (c *controller) deleteOrphanVM(vm driver.VMs, secretRef *corev1.Secret, kin
machineName = v
}

dvr := driver.NewCmiDriverClient(
dvr := driver.NewCMIDriverClient(
machineID,
kind,
secretRef,
machineClass,
machineName,
)

err := dvr.DeleteMachine()
err := dvr.DeleteMachine(machineID)
if err != nil {
glog.Errorf("Error while deleting VM on CP - %s. Shall retry in next safety controller sync.", err)
} else {
Expand Down
Loading