2018-09-21 10:26:04 -04:00
|
|
|
# Plugin Registration Service
|
|
|
|
|
|
2018-05-01 02:15:06 -04:00
|
|
|
This folder contains a utility, pluginwatcher, for Kubelet to register
|
|
|
|
|
different types of node-level plugins such as device plugins or CSI plugins.
|
|
|
|
|
It discovers plugins by monitoring inotify events under the directory returned by
|
2018-09-21 10:26:04 -04:00
|
|
|
kubelet.getPluginsDir(). We will refer to this directory as PluginsDir.
|
|
|
|
|
|
|
|
|
|
Plugins are expected to implement the gRPC registration service specified in
|
|
|
|
|
pkg/kubelet/apis/pluginregistration/v*/api.proto.
|
|
|
|
|
|
|
|
|
|
## Plugin Discovery
|
|
|
|
|
|
|
|
|
|
The pluginwatcher service will discover plugins in the PluginDir when they
|
|
|
|
|
place a socket in that directory or, at Kubelet start if the socket is already
|
|
|
|
|
there.
|
|
|
|
|
|
|
|
|
|
This socket filename should not start with a '.' as it will be ignored.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## gRPC Service Lifecycle
|
|
|
|
|
|
|
|
|
|
For any discovered plugin, kubelet will issue a Registration.GetInfo gRPC call
|
|
|
|
|
to get plugin type, name, endpoint and supported service API versions.
|
|
|
|
|
|
2019-03-09 08:25:08 -05:00
|
|
|
If any of the following steps in registration fails, on retry registration will
|
|
|
|
|
start from scratch:
|
|
|
|
|
- Registration.GetInfo is called against socket.
|
|
|
|
|
- Validate is called against internal plugin type handler.
|
|
|
|
|
- Register is called against internal plugin type handler.
|
|
|
|
|
- NotifyRegistrationStatus is called against socket to indicate registration result.
|
|
|
|
|
|
|
|
|
|
During plugin initialization phase, Kubelet will issue Plugin specific calls
|
|
|
|
|
(e.g: DevicePlugin::GetDevicePluginOptions).
|
2018-09-21 10:26:04 -04:00
|
|
|
|
|
|
|
|
Once Kubelet determines that it is ready to use your plugin it will issue a
|
|
|
|
|
Registration.NotifyRegistrationStatus gRPC call.
|
|
|
|
|
|
|
|
|
|
If the plugin removes its socket from the PluginDir this will be interpreted
|
2019-03-09 08:25:08 -05:00
|
|
|
as a plugin Deregistration. If any of the following steps in deregistration fails,
|
|
|
|
|
on retry deregistration will start from scratch:
|
|
|
|
|
- Registration.GetInfo is called against socket.
|
|
|
|
|
- DeRegisterPlugin is called against internal plugin type handler.
|
2018-05-01 02:15:06 -04:00
|
|
|
|
Add hierarchy support for plugin directory
it traverses and watch plugin directory and its sub directory recursively,
plugin socket file only need be unique within one directory,
- plugin socket directory
- |
- ---->sub directory 1
- | |
- | -----> socket1, socket2 ...
- ----->sub directory 2
- |
- ------> socket1, socket2 ...
the design itself allow sub directory be anything,
but in practical, each plugin type could just use one sub directory.
four bonus changes added as below
1. extract example handler out from test, it is easier to read the code
with the seperation.
2. there are two variables here: "Watcher" and "watcher".
"Watcher" is the plugin watcher, and "watcher" is the fsnotify watcher.
so rename the "watcher" to "fsWatcher" to make code easier to
understand.
3. change RegisterCallbackFn() return value order, it is
conventional to return error last, after this change,
the pkg/volume/csi is compliance with golint, so remove it
from hack/.golint_failures
4. refactor errors handling at invokeRegistrationCallbackAtHandler()
to make error message more clear.
2018-05-30 20:07:58 -04:00
|
|
|
|
2018-09-21 10:26:04 -04:00
|
|
|
## gRPC Service Overview
|
|
|
|
|
|
|
|
|
|
Here are the general rules that Kubelet plugin developers should follow:
|
|
|
|
|
- Run plugin as 'root' user. Currently creating socket under PluginsDir, a root owned
|
|
|
|
|
directory, requires plugin process to be running as 'root'.
|
Add hierarchy support for plugin directory
it traverses and watch plugin directory and its sub directory recursively,
plugin socket file only need be unique within one directory,
- plugin socket directory
- |
- ---->sub directory 1
- | |
- | -----> socket1, socket2 ...
- ----->sub directory 2
- |
- ------> socket1, socket2 ...
the design itself allow sub directory be anything,
but in practical, each plugin type could just use one sub directory.
four bonus changes added as below
1. extract example handler out from test, it is easier to read the code
with the seperation.
2. there are two variables here: "Watcher" and "watcher".
"Watcher" is the plugin watcher, and "watcher" is the fsnotify watcher.
so rename the "watcher" to "fsWatcher" to make code easier to
understand.
3. change RegisterCallbackFn() return value order, it is
conventional to return error last, after this change,
the pkg/volume/csi is compliance with golint, so remove it
from hack/.golint_failures
4. refactor errors handling at invokeRegistrationCallbackAtHandler()
to make error message more clear.
2018-05-30 20:07:58 -04:00
|
|
|
|
2018-05-01 02:15:06 -04:00
|
|
|
- The plugin name sent during Registration.GetInfo grpc should be unique
|
|
|
|
|
for the given plugin type (CSIPlugin or DevicePlugin).
|
Add hierarchy support for plugin directory
it traverses and watch plugin directory and its sub directory recursively,
plugin socket file only need be unique within one directory,
- plugin socket directory
- |
- ---->sub directory 1
- | |
- | -----> socket1, socket2 ...
- ----->sub directory 2
- |
- ------> socket1, socket2 ...
the design itself allow sub directory be anything,
but in practical, each plugin type could just use one sub directory.
four bonus changes added as below
1. extract example handler out from test, it is easier to read the code
with the seperation.
2. there are two variables here: "Watcher" and "watcher".
"Watcher" is the plugin watcher, and "watcher" is the fsnotify watcher.
so rename the "watcher" to "fsWatcher" to make code easier to
understand.
3. change RegisterCallbackFn() return value order, it is
conventional to return error last, after this change,
the pkg/volume/csi is compliance with golint, so remove it
from hack/.golint_failures
4. refactor errors handling at invokeRegistrationCallbackAtHandler()
to make error message more clear.
2018-05-30 20:07:58 -04:00
|
|
|
|
2018-09-21 10:26:04 -04:00
|
|
|
- The socket path needs to be unique within one directory, in normal case,
|
Add hierarchy support for plugin directory
it traverses and watch plugin directory and its sub directory recursively,
plugin socket file only need be unique within one directory,
- plugin socket directory
- |
- ---->sub directory 1
- | |
- | -----> socket1, socket2 ...
- ----->sub directory 2
- |
- ------> socket1, socket2 ...
the design itself allow sub directory be anything,
but in practical, each plugin type could just use one sub directory.
four bonus changes added as below
1. extract example handler out from test, it is easier to read the code
with the seperation.
2. there are two variables here: "Watcher" and "watcher".
"Watcher" is the plugin watcher, and "watcher" is the fsnotify watcher.
so rename the "watcher" to "fsWatcher" to make code easier to
understand.
3. change RegisterCallbackFn() return value order, it is
conventional to return error last, after this change,
the pkg/volume/csi is compliance with golint, so remove it
from hack/.golint_failures
4. refactor errors handling at invokeRegistrationCallbackAtHandler()
to make error message more clear.
2018-05-30 20:07:58 -04:00
|
|
|
each plugin type has its own sub directory, but the design does support socket file
|
|
|
|
|
under any sub directory of PluginSockDir.
|
2019-02-21 20:43:51 -05:00
|
|
|
|
2018-05-01 02:15:06 -04:00
|
|
|
- A plugin should clean up its own socket upon exiting or when a new instance
|
|
|
|
|
comes up. A plugin should NOT remove any sockets belonging to other plugins.
|
Add hierarchy support for plugin directory
it traverses and watch plugin directory and its sub directory recursively,
plugin socket file only need be unique within one directory,
- plugin socket directory
- |
- ---->sub directory 1
- | |
- | -----> socket1, socket2 ...
- ----->sub directory 2
- |
- ------> socket1, socket2 ...
the design itself allow sub directory be anything,
but in practical, each plugin type could just use one sub directory.
four bonus changes added as below
1. extract example handler out from test, it is easier to read the code
with the seperation.
2. there are two variables here: "Watcher" and "watcher".
"Watcher" is the plugin watcher, and "watcher" is the fsnotify watcher.
so rename the "watcher" to "fsWatcher" to make code easier to
understand.
3. change RegisterCallbackFn() return value order, it is
conventional to return error last, after this change,
the pkg/volume/csi is compliance with golint, so remove it
from hack/.golint_failures
4. refactor errors handling at invokeRegistrationCallbackAtHandler()
to make error message more clear.
2018-05-30 20:07:58 -04:00
|
|
|
|
2018-05-01 02:15:06 -04:00
|
|
|
- A plugin should make sure it has service ready for any supported service API
|
|
|
|
|
version listed in the PluginInfo.
|
Add hierarchy support for plugin directory
it traverses and watch plugin directory and its sub directory recursively,
plugin socket file only need be unique within one directory,
- plugin socket directory
- |
- ---->sub directory 1
- | |
- | -----> socket1, socket2 ...
- ----->sub directory 2
- |
- ------> socket1, socket2 ...
the design itself allow sub directory be anything,
but in practical, each plugin type could just use one sub directory.
four bonus changes added as below
1. extract example handler out from test, it is easier to read the code
with the seperation.
2. there are two variables here: "Watcher" and "watcher".
"Watcher" is the plugin watcher, and "watcher" is the fsnotify watcher.
so rename the "watcher" to "fsWatcher" to make code easier to
understand.
3. change RegisterCallbackFn() return value order, it is
conventional to return error last, after this change,
the pkg/volume/csi is compliance with golint, so remove it
from hack/.golint_failures
4. refactor errors handling at invokeRegistrationCallbackAtHandler()
to make error message more clear.
2018-05-30 20:07:58 -04:00
|
|
|
|
2018-05-01 02:15:06 -04:00
|
|
|
- For an example plugin implementation, take a look at example_plugin.go
|
|
|
|
|
included in this directory.
|
2018-09-21 10:26:04 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# Kubelet Interface
|
|
|
|
|
|
|
|
|
|
For any kubelet components using the pluginwatcher module, you will need to
|
|
|
|
|
implement the PluginHandler interface defined in the types.go file.
|
|
|
|
|
|
|
|
|
|
The interface is documented and the implementations are registered with the
|
|
|
|
|
pluginwatcher module in kubelet.go by calling AddHandler(pluginType, handler).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The lifecycle follows a simple state machine:
|
|
|
|
|
|
|
|
|
|
Validate -> Register -> DeRegister
|
|
|
|
|
^ +
|
|
|
|
|
| |
|
|
|
|
|
+--------- +
|
|
|
|
|
|
|
|
|
|
The pluginwatcher calls the functions with the received plugin name, supported
|
|
|
|
|
service API versions and the endpoint to call the plugin on.
|
|
|
|
|
|
|
|
|
|
The Kubelet component that receives this callback can acknowledge or reject
|
|
|
|
|
the plugin according to its own logic, and use the socket path to establish
|
|
|
|
|
its service communication with any API version supported by the plugin.
|