Skip to content
This repository has been archived by the owner on Nov 9, 2020. It is now read-only.

Check vmciVersion between client and server. #1046

Merged
merged 5 commits into from
Mar 24, 2017

Conversation

lipingxue
Copy link
Contributor

This PR includes:

  1. Add a new field "version" in struct "requestVmci" to store the current version of VMCI.
  2. In ESX side, when receiving the request, read the version from client request and compare it against the server version of VMCI. If the VMCI version between client and server does not match, return with appropriate error.

Fixed #318

@lipingxue
Copy link
Contributor Author

I did the unit testing manually with managed plugin.
Server VMCI version which is set in code is "12".

Case1: set client VMCI version to "11" through environment variable when install the managed plugin

  1. install the managed plugin
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker plugin install --grant-all-permissions    lipingxue/docker-volume-vsphere:vmci_test  VDVS_LOG_LEVEL=debug  VMCI_VERSION=11
vmci_test: Pulling from lipingxue/docker-volume-vsphere
32627b4ce94d: Download complete
Digest: sha256:c798c643bacd33786dd118ca7053e50a0c379772cd34c23e969b18469af422a3
Status: Downloaded newer image for lipingxue/docker-volume-vsphere:vmci_test
Installed plugin lipingxue/docker-volume-vsphere:vmci_test
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin#
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin#
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin#
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker plugin ls
ID                  NAME                                        DESCRIPTION                           ENABLED
705693b72f31        lipingxue/docker-volume-vsphere:vmci_test   VMWare vSphere Docker Volume plugin   true
  1. create a volume with this plugin, which should fail
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker volume create --driver=lipingxue/docker-volume-vsphere:vmci_test  --name=vol1
Error response from daemon: create vol1: VolumeDriver.Create: Client version (11) is lower than server version (12), please upgrade client.

Case2: set client VMCI version in to "13" through environment variable when install the managed plugin

  1. install the managed plugin
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker plugin install --grant-all-permissions    lipingxue/docker-volume-vsphere:vmci_test  VDVS_LOG_LEVEL=debug  VMCI_VERSION=13
vmci_test: Pulling from lipingxue/docker-volume-vsphere
32627b4ce94d: Download complete
Digest: sha256:c798c643bacd33786dd118ca7053e50a0c379772cd34c23e969b18469af422a3
Status: Downloaded newer image for lipingxue/docker-volume-vsphere:vmci_test
Installed plugin lipingxue/docker-volume-vsphere:vmci_test
  1. create a volume with this plugin, which should fail
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker volume create --driver=lipingxue/docker-volume-vsphere:vmci_test  --name=vol1
Error response from daemon: create vol1: VolumeDriver.Create: Client version (13) is higher than server version (12), please upgrade server.

Case3: install managed plugin without setting environment variable

  1. install the managed plugin
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker plugin install --grant-all-permissions    lipingxue/docker-volume-vsphere:vmci_test  VDVS_LOG_LEVEL=debug
vmci_test: Pulling from lipingxue/docker-volume-vsphere
32627b4ce94d: Download complete
Digest: sha256:c798c643bacd33786dd118ca7053e50a0c379772cd34c23e969b18469af422a3
Status: Downloaded newer image for lipingxue/docker-volume-vsphere:vmci_test
Installed plugin lipingxue/docker-volume-vsphere:vmci_test
  1. create a volume with this plugin, which should succeed
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker volume create --driver=lipingxue/docker-volume-vsphere:vmci_test  --name=vol1
vol1
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin#
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin#
root@sc-rdops-vm18-dhcp-57-89:/tmp/plugin# docker volume ls
DRIVER                                      VOLUME NAME
lipingxue/docker-volume-vsphere:vmci_test   vol1@datastore2

@lipingxue
Copy link
Contributor Author

Please review it @msterin @shaominchen @shuklanirdesh82

@@ -104,6 +104,10 @@
MAX_SKIP_COUNT = 16 # max retries on VMCI Get Ops failures
VMDK_ADAPTER_TYPE = 'busLogic' # default adapter type

#VMCI Version
# !!! server side VMCI version, need to change according with client side version !!!
VMCI_VERSION = "12"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: don't we need to set as 13 as we are approaching to 0.13 release?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not really matter. To avoid confusion, I suggest naming it PROTOCOL_VERSION and assigning a value of 2 . It has nothing to do with release number

Also -please change comment to so something like Server side understand protocol version. If you are changing client/server protocol we use over VMCI, PLEASE DO NOT FORGET TO CHANGE IT FOR CLIENT in file <file name> !

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VMCI_VERSION is definitely confusing - we are not really dealing with different VMCI versions. PROTOCOL_VERSION is much better, but it's still a little bit confusing to me - what's exactly the "protocol"? When we say "If you are changing client/server protocol", we actually mean "If the version of your client plug-in doesn't match with the version of your server driver". So personally I feel we should not even use the term "protocol" here.

Since we are actually handling the version control between our client plugin and server driver, why can't we simply define a internal version number (name doesn't matter, just a property in build infrastructure), which should be compiled into client plugin as a constant, say CLIENT_VERSION, and into server driver as another constant, say SERVER_VERSION. When client sends requests to the server, the CLIENT_VERSION should be sent to the server over VMCI. And then server will compare the CLIENT_VERSION it receives with its own SERVER_VERSION, and decide if there's a version mismatch.

Comments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Change the name to "PROTOCOL_VERSION".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any feedback/response to my comments above :) @lipingxue @msterin

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Furthermore, I feel our client plugin and server driver are two independent components running in different user spaces. So it makes sense to maintain two separate version numbers. Also to improve the flexibility of inter-op, the version matching logic should consider backward compatibility, i.e. SERVER_VERSION should be compatible with lower CLIENT_VERSION. We may decide a version gap that we can support - let's say 3, then SERVER_VERSION 5 will work with CLIENT_VERSION 5, 4 and 3, but won't work with CLIENT_VERSION 2.

Copy link
Contributor

@msterin msterin Mar 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shaominchen - the only difference I see between the current code and your suggestion is that you want to rename the vmdk_ops.py:PROTOCOL_VERSION to SERVER_PROTOCOL_VERSION (note - it is NOT the version of server. It is the version of over-VMCI protocol the server expects) .
and to rename esx_vmdkcmd.go:protocolCurrentVersion to clientProtocolVersion.

Is it what you are saying ?

I agree, it makes the code easier to read and understand.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with SERVER_PROTOCOL_VERSION and CLIENT_PROTOCOL_VERSION. The main point here is to distinguish the version numbers between client and server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. @lipingxue - please rename , unless you have some reasons not to (and then share them please )

{
"name": "VMCI_VERSION",
"description": "Request VMCI version",
"value": "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it better to set default value for the version?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually - this one is ONLY for debugging and testing, so we can set it to something and make sure the versions mismatch handling is correct

@lipingxue -- please change name to something more obvious (that it's for test only) and add proper comment in description. Something like TEST_PROTOCOL_VERSION

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client MUST have the version defined in the code. Please do not rely on the env variable for this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Change the name to "TEST_PROTOCOL_VERSION".

@@ -104,6 +104,10 @@
MAX_SKIP_COUNT = 16 # max retries on VMCI Get Ops failures
VMDK_ADAPTER_TYPE = 'busLogic' # default adapter type

#VMCI Version
# !!! server side VMCI version, need to change according with client side version !!!
VMCI_VERSION = "12"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not really matter. To avoid confusion, I suggest naming it PROTOCOL_VERSION and assigning a value of 2 . It has nothing to do with release number

Also -please change comment to so something like Server side understand protocol version. If you are changing client/server protocol we use over VMCI, PLEASE DO NOT FORGET TO CHANGE IT FOR CLIENT in file <file name> !

version = req["version"]
if version != VMCI_VERSION:
if int(version) < int(VMCI_VERSION):
reply_string = err("Client version ({0}) is lower than server version ({1}), please upgrade client.".format(version, VMCI_VERSION))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget that it is the message the Docker user will see, so we need to be specific about where this message is coming from.
Something like "vSphere Docker Volume Service client version (1) is older than server version (2) , please update the client" and "vSphere Docker Volume Service client version (3) is newer than server version (2) , please update the server"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if int(version) < int(VMCI_VERSION):
reply_string = err("Client version ({0}) is lower than server version ({1}), please upgrade client.".format(version, VMCI_VERSION))
else:
reply_string = err("Client version ({0}) is higher than server version ({1}), please upgrade server.".format(version, VMCI_VERSION))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if the order of {} is the same as the order of params, no need for numbers inside of {}
i.e. this would be also correct and more pythonish:

  reply_string = 
       err("vSphere Docker Volume Service client version ({}) is newer than server version ({}) , please update the server".format(version, VMCI_VERSION))

{
"name": "VMCI_VERSION",
"description": "Request VMCI version",
"value": "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually - this one is ONLY for debugging and testing, so we can set it to something and make sure the versions mismatch handling is correct

@lipingxue -- please change name to something more obvious (that it's for test only) and add proper comment in description. Something like TEST_PROTOCOL_VERSION


var versionEnv = os.Getenv("VMCI_VERSION")
log.Debugf("Run get request: version=%s", versionEnv)
// TODO: versionEnv need to read from enviroment variable when Nirdesh's Makefile is ready
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please do not leave names in comments. It's better to open an issue and simply refer it.

{
"name": "VMCI_VERSION",
"description": "Request VMCI version",
"value": "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client MUST have the version defined in the code. Please do not rely on the env variable for this

// TODO: versionEnv need to read from enviroment variable when Nirdesh's Makefile is ready
// versionEnv = "13"
var vmciVersion string
if versionEnv == "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should not be picked up from environment.
You should do something like

  protocolVersion := os.Getenv("TEST_PROTOCOL_VERSION")
  if protocolVersion == "" {
     protocolVersion = <some hardcoded constant from const() section in the file>
 }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -1469,6 +1473,15 @@ def execRequestThread(client_socket, cartel, request):
reply_string = {u'Error': "Failed to parse json '%s'." % request}
send_vmci_reply(client_socket, reply_string)
else:
logging.debug("execRequestThread: req=%s", req)
version = req["version"]
if version != VMCI_VERSION:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too strict expecting user to have exact same version of plugin and esx service.

I think we need "MIN_SUPPORTED_VERSION" and "MAX_SUPPORTED_VERSION" and need to maintain forward/backward compatibility for at lease 1 release. For e.g. for upcoming release, 0.13 Plugin should be compatible with 0.12 Server or vice-versa.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently protocol version IS NOT a release version and DOES NOT change with tagging or releases. It is a hardcoded (on both sides) version , and if it mismatches CURRENTLY we just decline. If/when we change the protocol and support mutli-protocol server , we will adjust accordingly

Check vmcVersion between client and server.
Check vmciVersion between client and server.

Add enviroment variable "VMCI_VERSION" in config.json file and some minor change.

Change the default debug level back to "INFO".

Small fix.
@lipingxue lipingxue force-pushed the vmci_version_control.liping branch 2 times, most recently from 6a9207b to 6a363fa Compare March 22, 2017 05:03
Address comments from Mark.

Address comments from Mark.

Remove unused code.

One more fix.
@lipingxue
Copy link
Contributor Author

Comments have been addressed, please take a look again. @msterin @shaominchen @shuklanirdesh82

Copy link
Contributor

@msterin msterin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. A couple of nits. One (remaining) question is - how it is going to behave if the curent code (with no version support) works vs. the new code (with version support). Will it fail - which is OK as long as it's clear what to do ?

}]
},
{
"name": "TEST_PROTOCOL_VERSION",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit (since it's not for customers) Can we stick with VDVS_ as a prefix for all keys ?"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

maxRetryCount = 5
commBackendName string = "vsocket"
maxRetryCount = 5
protocolCurrentVersion = "2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the comment similar to the one you've added on the server side

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

)

// A request to be passed to ESX service
type requestToVmci struct {
Ops string `json:"cmd"`
Details VolumeInfo `json:"details"`
Version string `json:"version"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so will it break compat with existng version ? Do you think an optional "version" is better, and the lack of version indicates V1 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

#VMCI Version
# !!! server side VMCI version, need to change according with client side version !!!
VMCI_VERSION = "12"
# Server side understand protocol version. If you are changing client/server protocol we use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I still feel "changing client/server protocol we use over VMCI" is a little bit confusing. As I have already commented in my previous comments, I suggest to use CLIENT_VERSION in VM plugin, and SERVER_VERSION in ESX driver. Please see my previous comments for more detail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"VMCI_VERSION" has been changed to "PROTOCOL_VERSION". I think both the client and server side use the "PROTOCOL_VERSION" is clear enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am actually with Sam here. Technically, there is no difference. Clarity-wise, with consts named properly (SERVER_PROTOCOL_VERSION and clientProtocolVersion) it is really much easier to understand

@lipingxue
Copy link
Contributor Author

Added code to handle the case that client does not have version(v1 client), and do the test manually.

root@sc-rdops-vm18-dhcp-57-89:~# docker volume create --driver=vsphere --name=vol4
Error response from daemon: create vol4: VolumeDriver.Create: vSphere Docker Volume Service client is too old, and cannot talk to server with version (2), please update the client.

Address more comments from Mark.

Small fix.
Copy link
Contributor

@msterin msterin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing my comments.
A fresh nit (for the fresh code), but main request is to rename the vars per @shaominchen suggestion.
Other that that, LGTM

"please update the server.".format(version, PROTOCOL_VERSION))
send_vmci_reply(client_socket, reply_string)
else:
reply_string = err("vSphere Docker Volume Service client is too old, and cannot talk to server with version ({}), "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can it be combined with line 1481 ?
Something lie "if verion not in req. or int(version) < int(clientVersion) { ... } else if ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message vSphere Docker Volume Service client version ({}) is older than server version ({}) need to fill the client version. If client is too old (V1 client), there is no version available. Should we show the client version as None or show different error message as I did in the current code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both approaches are fine (which is why it is a nit :-)).
My preference is to have the same message , and instead of "None" show ("1") since we start counting from 2 :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, got it. Will address it.

maxRetryCount = 5
// Server side understand protocol version. If you are changing client/server protocol we use
// over VMCI, PLEASE DO NOT FORGET TO CHANGE IT FOR SERVER in file <vmdk_ops.py> !
protocolCurrentVersion = "2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree with @shaominchen , calling clientProtocolVersion makes it much easier to comprehend

Address additional comments from Mark and Sam.

Small fix.
@lipingxue
Copy link
Contributor Author

@msterin @shaominchen I have address your comments, please take a look.

Copy link
Contributor

@msterin msterin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Sorry, last comment related to rename - it has to be done for the 'version' var on the server as well. Just name it 'client_protocol_version'. A couple of small nits also in the comments

version = req["version"] if "version" in req else "1"
logging.debug("execRequestThread: version=%s", version)
if version != SERVER_PROTOCOL_VERSION:
if not version or int(version) < int(SERVER_PROTOCOL_VERSION):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version is guaranted to be set in L1478, no need to do if 'not version' here. Should be simple
`if int(version) < int(SERVER_PROTOCOL_VERSION)

@@ -1469,6 +1473,19 @@ def execRequestThread(client_socket, cartel, request):
reply_string = {u'Error': "Failed to parse json '%s'." % request}
send_vmci_reply(client_socket, reply_string)
else:
logging.debug("execRequestThread: req=%s", req)
# If req from client does not include version number, set the version to "1" by default
version = req["version"] if "version" in req else "1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to make all consistent - can you rename 'version' -> 'client_protocol_version' ?
then the comparison would be 'if client_version < SERVER_PROTOCOL_VERSION'

logging.debug("execRequestThread: version=%s", version)
if version != SERVER_PROTOCOL_VERSION:
if not version or int(version) < int(SERVER_PROTOCOL_VERSION):
reply_string = err("vSphere Docker Volume Service client version ({}) is older than server version ({}), "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, SERVER_PROTOCOL_VERSION is int() already, isn't it?
I suggest setting client_protocol_version (L 1478) to int as well
client_protocol_version = int(req["version"] if "version" in req else 1 and droping int() conversion in other places

Address the comments from Mark to rename the variable.

Small fix.
@lipingxue
Copy link
Contributor Author

@msterin I have renamed the variable. Please take another look :)

Copy link
Contributor

@shaominchen shaominchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice and clean! Thanks for addressing the comments.

Copy link
Contributor

@shuklanirdesh82 shuklanirdesh82 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@pdhamdhere
Copy link
Contributor

CI is failing with errors unrelated to this PR.

plugin_sanity_test: [ERROR] error has occurred while fetching created plugin name..
         please make sure plugin is built correctly or not
bash: make: command not found
make[1]: *** [deploy-vm-plugin] Error 127
make: *** [deploy-vm-plugin] Error 2

Merging.

@pdhamdhere pdhamdhere merged commit 07b6371 into master Mar 24, 2017
@pdhamdhere pdhamdhere deleted the vmci_version_control.liping branch March 24, 2017 16:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants