Repository: kumahq/kuma
Pull request #1192 (2020-11-22 20:46:38)

feat(kuma-dp): Kuma DP + Envoy version in Dataplane Insights (#1112)
Signed-off-by: Jacek Ewertowski <jacek.ewertowski1@gmail.com>

### Summary

This PR resolves issue #1112.

### Full changelog

* Implement reading envoy version on Kuma DP startup.
* Send Kuma DP and Envoy version in bootstrap request.
* Generate bootstrap with KumaDP and Envoy version.
* Store version of Envoy and Kuma sent in `DiscoveryRequest.Node.Metadata`

jakubdyszkiewicz: run `make check` to cleanup the code.

Don't worry about failing E2E or minikube tests for now. It's on our side
jewertow: Thank you very much for the code review. I fixed imports and the step `make check` passes again.
I will continue work on this PR this week.
jewertow: I need your help @jakubdyszkiewicz.
I have read the [documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/discovery.proto#envoy-api-msg-discoveryrequest) of `DiscoveryRequest` and I am not sure which property of `DiscoveryRequest` is a proper place for version.
jakubdyszkiewicz: Hey @jewertow let's do `node.metadata`. I looked into Envoy code and don't really see any references for `user_agent_build_version` in the code so I don't see the benefit of fighting with semver parsing etc.
jewertow: @jakubdyszkiewicz how command `kumactl inspect dataplanes` should work? 
Should it always return 6 additional columns? Maybe it would be better to add `-version/--version` flag to this command and return columns with versions when the flag is passed?
jakubdyszkiewicz: @jewertow you brought a good question about CLI. Let's do this a separate PR and let me create an issue to discuss.
jakubdyszkiewicz: please merge origin/master. CI should be green then
nickolaev: @jewertow would you mind merging `master` please? We will consider including this one after we get 1.0.2 released today.

Also, please do to put WIP in the name of the PR, being a `draft` is already good enough.
jewertow: @nickolaev I merged master into this branch.

Patch:
diff --git a/api/mesh/v1alpha1/dataplane_insight.pb.go b/api/mesh/v1alpha1/dataplane_insight.pb.go
index 7526322e5..7daaf77a4 100644
--- a/api/mesh/v1alpha1/dataplane_insight.pb.go
+++ b/api/mesh/v1alpha1/dataplane_insight.pb.go
@@ -151,10 +151,12 @@ type DiscoverySubscription struct {
 	// Time when a given Dataplane disconnected from the Control Plane.
 	DisconnectTime *timestamp.Timestamp `protobuf:"bytes,4,opt,name=disconnect_time,json=disconnectTime,proto3" json:"disconnect_time,omitempty"`
 	// Status of the ADS subscription.
-	Status               *DiscoverySubscriptionStatus `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}                     `json:"-"`
-	XXX_unrecognized     []byte                       `json:"-"`
-	XXX_sizecache        int32                        `json:"-"`
+	Status *DiscoverySubscriptionStatus `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"`
+	// Version of Envoy and Kuma dataplane
+	Version              *Version `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
 func (m *DiscoverySubscription) Reset()         { *m = DiscoverySubscription{} }
@@ -217,6 +219,13 @@ func (m *DiscoverySubscription) GetStatus() *DiscoverySubscriptionStatus {
 	return nil
 }
 
+func (m *DiscoverySubscription) GetVersion() *Version {
+	if m != nil {
+		return m.Version
+	}
+	return nil
+}
+
 // DiscoverySubscriptionStatus defines status of an ADS subscription.
 type DiscoverySubscriptionStatus struct {
 	// Time when status of a given ADS subscription was most recently updated.
@@ -362,12 +371,172 @@ func (m *DiscoveryServiceStats) GetResponsesRejected() uint64 {
 	return 0
 }
 
+type Version struct {
+	DpVersion            *KumaDpVersion `protobuf:"bytes,1,opt,name=dpVersion,proto3" json:"dpVersion,omitempty"`
+	Envoy                *EnvoyVersion  `protobuf:"bytes,2,opt,name=envoy,proto3" json:"envoy,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
+	XXX_unrecognized     []byte         `json:"-"`
+	XXX_sizecache        int32          `json:"-"`
+}
+
+func (m *Version) Reset()         { *m = Version{} }
+func (m *Version) String() string { return proto.CompactTextString(m) }
+func (*Version) ProtoMessage()    {}
+func (*Version) Descriptor() ([]byte, []int) {
+	return fileDescriptor_35794f05b529b342, []int{4}
+}
+
+func (m *Version) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Version.Unmarshal(m, b)
+}
+func (m *Version) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Version.Marshal(b, m, deterministic)
+}
+func (m *Version) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Version.Merge(m, src)
+}
+func (m *Version) XXX_Size() int {
+	return xxx_messageInfo_Version.Size(m)
+}
+func (m *Version) XXX_DiscardUnknown() {
+	xxx_messageInfo_Version.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Version proto.InternalMessageInfo
+
+func (m *Version) GetDpVersion() *KumaDpVersion {
+	if m != nil {
+		return m.DpVersion
+	}
+	return nil
+}
+
+func (m *Version) GetEnvoy() *EnvoyVersion {
+	if m != nil {
+		return m.Envoy
+	}
+	return nil
+}
+
+type KumaDpVersion struct {
+	Version              string   `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
+	GitTag               string   `protobuf:"bytes,2,opt,name=gitTag,proto3" json:"gitTag,omitempty"`
+	GitCommit            string   `protobuf:"bytes,3,opt,name=gitCommit,proto3" json:"gitCommit,omitempty"`
+	BuildDate            string   `protobuf:"bytes,4,opt,name=buildDate,proto3" json:"buildDate,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *KumaDpVersion) Reset()         { *m = KumaDpVersion{} }
+func (m *KumaDpVersion) String() string { return proto.CompactTextString(m) }
+func (*KumaDpVersion) ProtoMessage()    {}
+func (*KumaDpVersion) Descriptor() ([]byte, []int) {
+	return fileDescriptor_35794f05b529b342, []int{5}
+}
+
+func (m *KumaDpVersion) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_KumaDpVersion.Unmarshal(m, b)
+}
+func (m *KumaDpVersion) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_KumaDpVersion.Marshal(b, m, deterministic)
+}
+func (m *KumaDpVersion) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_KumaDpVersion.Merge(m, src)
+}
+func (m *KumaDpVersion) XXX_Size() int {
+	return xxx_messageInfo_KumaDpVersion.Size(m)
+}
+func (m *KumaDpVersion) XXX_DiscardUnknown() {
+	xxx_messageInfo_KumaDpVersion.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_KumaDpVersion proto.InternalMessageInfo
+
+func (m *KumaDpVersion) GetVersion() string {
+	if m != nil {
+		return m.Version
+	}
+	return ""
+}
+
+func (m *KumaDpVersion) GetGitTag() string {
+	if m != nil {
+		return m.GitTag
+	}
+	return ""
+}
+
+func (m *KumaDpVersion) GetGitCommit() string {
+	if m != nil {
+		return m.GitCommit
+	}
+	return ""
+}
+
+func (m *KumaDpVersion) GetBuildDate() string {
+	if m != nil {
+		return m.BuildDate
+	}
+	return ""
+}
+
+type EnvoyVersion struct {
+	Version              string   `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
+	Build                string   `protobuf:"bytes,2,opt,name=build,proto3" json:"build,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *EnvoyVersion) Reset()         { *m = EnvoyVersion{} }
+func (m *EnvoyVersion) String() string { return proto.CompactTextString(m) }
+func (*EnvoyVersion) ProtoMessage()    {}
+func (*EnvoyVersion) Descriptor() ([]byte, []int) {
+	return fileDescriptor_35794f05b529b342, []int{6}
+}
+
+func (m *EnvoyVersion) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_EnvoyVersion.Unmarshal(m, b)
+}
+func (m *EnvoyVersion) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_EnvoyVersion.Marshal(b, m, deterministic)
+}
+func (m *EnvoyVersion) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_EnvoyVersion.Merge(m, src)
+}
+func (m *EnvoyVersion) XXX_Size() int {
+	return xxx_messageInfo_EnvoyVersion.Size(m)
+}
+func (m *EnvoyVersion) XXX_DiscardUnknown() {
+	xxx_messageInfo_EnvoyVersion.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_EnvoyVersion proto.InternalMessageInfo
+
+func (m *EnvoyVersion) GetVersion() string {
+	if m != nil {
+		return m.Version
+	}
+	return ""
+}
+
+func (m *EnvoyVersion) GetBuild() string {
+	if m != nil {
+		return m.Build
+	}
+	return ""
+}
+
 func init() {
 	proto.RegisterType((*DataplaneInsight)(nil), "kuma.mesh.v1alpha1.DataplaneInsight")
 	proto.RegisterType((*DataplaneInsight_MTLS)(nil), "kuma.mesh.v1alpha1.DataplaneInsight.MTLS")
 	proto.RegisterType((*DiscoverySubscription)(nil), "kuma.mesh.v1alpha1.DiscoverySubscription")
 	proto.RegisterType((*DiscoverySubscriptionStatus)(nil), "kuma.mesh.v1alpha1.DiscoverySubscriptionStatus")
 	proto.RegisterType((*DiscoveryServiceStats)(nil), "kuma.mesh.v1alpha1.DiscoveryServiceStats")
+	proto.RegisterType((*Version)(nil), "kuma.mesh.v1alpha1.Version")
+	proto.RegisterType((*KumaDpVersion)(nil), "kuma.mesh.v1alpha1.KumaDpVersion")
+	proto.RegisterType((*EnvoyVersion)(nil), "kuma.mesh.v1alpha1.EnvoyVersion")
 }
 
 func init() {
@@ -375,44 +544,53 @@ func init() {
 }
 
 var fileDescriptor_35794f05b529b342 = []byte{
-	// 623 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdf, 0x4e, 0x13, 0x4f,
-	0x14, 0xc7, 0xb3, 0xed, 0xc2, 0x8f, 0xdf, 0x20, 0x88, 0x93, 0x00, 0x4b, 0x89, 0x91, 0x34, 0x21,
-	0x41, 0x13, 0x77, 0x83, 0xc6, 0x2b, 0x62, 0x8c, 0x05, 0x63, 0x48, 0x30, 0xea, 0x14, 0x6f, 0xb8,
-	0x70, 0x33, 0x9d, 0x39, 0xb4, 0x23, 0xdb, 0x99, 0x75, 0x66, 0x5a, 0xf5, 0x15, 0x7c, 0x02, 0x1f,
-	0x80, 0x27, 0xf0, 0x5d, 0x7c, 0x19, 0x6e, 0x34, 0x33, 0xbb, 0x6d, 0x17, 0x85, 0x42, 0xaf, 0xfa,
-	0xe7, 0x9c, 0xcf, 0xf7, 0x9c, 0xf3, 0xdd, 0x6f, 0x8b, 0xb6, 0xfb, 0x60, 0x7a, 0xc9, 0x70, 0x97,
-	0x66, 0x79, 0x8f, 0xee, 0x26, 0x9c, 0x5a, 0x9a, 0x67, 0x54, 0x42, 0x2a, 0xa4, 0x11, 0xdd, 0x9e,
-	0x8d, 0x73, 0xad, 0xac, 0xc2, 0xf8, 0x6c, 0xd0, 0xa7, 0xb1, 0xeb, 0x8d, 0x47, 0xbd, 0x8d, 0x07,
-	0x5d, 0xa5, 0xba, 0x19, 0x24, 0xbe, 0xa3, 0x33, 0x38, 0x4d, 0xac, 0xe8, 0x83, 0xb1, 0xb4, 0x9f,
-	0x17, 0x50, 0x63, 0x7d, 0x48, 0x33, 0xc1, 0xa9, 0x85, 0x64, 0xf4, 0xa6, 0x28, 0x34, 0xcf, 0xeb,
-	0x68, 0xe5, 0x60, 0x34, 0xe9, 0xb0, 0x18, 0x84, 0xdf, 0xa2, 0x25, 0x33, 0xe8, 0x18, 0xa6, 0x45,
-	0x6e, 0x85, 0x92, 0x26, 0x0a, 0xb6, 0xea, 0x3b, 0x8b, 0x4f, 0x1e, 0xc6, 0xff, 0x8e, 0x8e, 0x0f,
-	0x84, 0x61, 0x6a, 0x08, 0xfa, 0x5b, 0xbb, 0x42, 0x90, 0xcb, 0x3c, 0x7e, 0x8e, 0xc2, 0xfe, 0xf1,
-	0x51, 0x3b, 0xaa, 0x6d, 0x05, 0xd7, 0xea, 0xfc, 0xb5, 0x44, 0xfc, 0xe6, 0xf8, 0xa8, 0x4d, 0x3c,
-	0xd6, 0xf8, 0x1d, 0xa0, 0xd0, 0x7d, 0xc4, 0x27, 0x68, 0x93, 0x81, 0xb6, 0xe2, 0x54, 0x30, 0x6a,
-	0x21, 0x85, 0xaf, 0xb9, 0xd0, 0xd4, 0x8d, 0x48, 0xdd, 0xc1, 0x51, 0xe0, 0xe5, 0x1b, 0x71, 0xe1,
-	0x46, 0x3c, 0x72, 0x23, 0x3e, 0x1e, 0xb9, 0x41, 0x36, 0x2a, 0xf8, 0xab, 0x31, 0xed, 0xea, 0xf8,
-	0x23, 0xba, 0x9f, 0x51, 0x63, 0xd3, 0xea, 0x00, 0x0d, 0x5d, 0x90, 0x50, 0x34, 0x95, 0xcb, 0x4f,
-	0x53, 0xdf, 0x74, 0x02, 0xfb, 0x13, 0x9e, 0x54, 0x70, 0xbc, 0x87, 0x36, 0xae, 0x93, 0x36, 0x51,
-	0x7d, 0x2b, 0xd8, 0x59, 0x22, 0x11, 0xbb, 0x9a, 0x35, 0xcd, 0x5f, 0x35, 0xb4, 0x7a, 0xa5, 0xd3,
-	0x78, 0x1d, 0xd5, 0x04, 0xf7, 0x97, 0xff, 0xdf, 0xfa, 0xef, 0xa2, 0x15, 0xea, 0xda, 0x4a, 0x40,
-	0x6a, 0x82, 0xe3, 0x16, 0xda, 0x60, 0x4a, 0x5a, 0xad, 0xb2, 0x74, 0x1c, 0x23, 0x4b, 0x25, 0x83,
-	0x54, 0x70, 0x7f, 0x4b, 0xa5, 0x7f, 0xad, 0xec, 0x7c, 0x57, 0x3e, 0x00, 0xdf, 0x77, 0xc8, 0xf1,
-	0x6b, 0x74, 0x87, 0x29, 0x29, 0x81, 0xd9, 0xc2, 0xe0, 0xfa, 0x4d, 0x16, 0xb4, 0x16, 0x2e, 0x5a,
-	0x73, 0x3f, 0x83, 0xda, 0x42, 0x40, 0x16, 0x4b, 0xd2, 0x9b, 0xbb, 0x8f, 0xee, 0x72, 0xb7, 0x7e,
-	0x45, 0x2b, 0xbc, 0xd1, 0xce, 0xe5, 0x09, 0xe2, 0x45, 0xde, 0xa3, 0x79, 0x63, 0xa9, 0x1d, 0x98,
-	0x68, 0xce, 0xb3, 0xc9, 0xad, 0xf3, 0xd8, 0xf6, 0x98, 0x5f, 0xee, 0x7b, 0xe0, 0x0e, 0x2e, 0x85,
-	0x9a, 0x3f, 0xea, 0x68, 0x73, 0x0a, 0x81, 0x0f, 0xd0, 0x8a, 0x0f, 0xc5, 0x20, 0x77, 0xbf, 0x99,
-	0xdb, 0xa6, 0x6c, 0xd9, 0x31, 0x1f, 0x3c, 0xe2, 0x17, 0x7f, 0x81, 0xe6, 0xac, 0xb2, 0x34, 0x9b,
-	0x9a, 0xff, 0xf1, 0x16, 0xa0, 0x87, 0x82, 0x81, 0x5b, 0xc0, 0x90, 0x82, 0xc3, 0x7b, 0xa8, 0xce,
-	0xb8, 0x29, 0xed, 0x9f, 0x01, 0x77, 0x94, 0x83, 0x81, 0x9b, 0xd2, 0xef, 0x59, 0x60, 0x28, 0xe0,
-	0x8c, 0x8f, 0x0c, 0x9f, 0x05, 0xce, 0x0a, 0x58, 0x73, 0x13, 0xcd, 0xcf, 0x0c, 0x6b, 0x6e, 0x9a,
-	0xe7, 0x41, 0x35, 0xf2, 0x95, 0x32, 0xde, 0x46, 0xcb, 0x1a, 0x4c, 0xae, 0xa4, 0x01, 0x93, 0x1a,
-	0x90, 0xd6, 0x3f, 0x92, 0x90, 0x2c, 0x8d, 0xbf, 0x6d, 0x83, 0xb4, 0xf8, 0x19, 0x5a, 0x9b, 0xb4,
-	0x51, 0x76, 0x26, 0xd5, 0x97, 0x0c, 0x78, 0x17, 0x8a, 0xf4, 0x87, 0x64, 0x75, 0x5c, 0x7d, 0x59,
-	0x29, 0xe2, 0xc7, 0x08, 0x4f, 0x30, 0x0d, 0x9f, 0x80, 0x59, 0xe0, 0xde, 0xfa, 0x90, 0xdc, 0x1b,
-	0x57, 0x48, 0x59, 0x68, 0x3d, 0x3a, 0xd9, 0xe9, 0x0a, 0xdb, 0x1b, 0x74, 0x62, 0xa6, 0xfa, 0x89,
-	0x3b, 0xb1, 0xf7, 0xd9, 0xbf, 0x24, 0x34, 0x17, 0xc9, 0xa5, 0xbf, 0xf4, 0xce, 0xbc, 0xcf, 0xca,
-	0xd3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x19, 0x23, 0x3d, 0xe8, 0xea, 0x05, 0x00, 0x00,
+	// 762 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x95, 0x5d, 0x4f, 0x13, 0x4b,
+	0x18, 0xc7, 0xb3, 0x7d, 0x83, 0x0e, 0x94, 0xc3, 0x99, 0x1c, 0xa0, 0xb4, 0xe7, 0xe4, 0xd4, 0x26,
+	0x24, 0x68, 0xe2, 0x6e, 0xd0, 0xe0, 0x0d, 0x51, 0x62, 0x29, 0x31, 0x44, 0x8c, 0x3a, 0xad, 0x5e,
+	0x70, 0x61, 0x33, 0xdd, 0x19, 0xb6, 0x23, 0xfb, 0xe6, 0xce, 0x6c, 0x95, 0x0b, 0x6f, 0xbc, 0x34,
+	0x7e, 0x00, 0x3f, 0x00, 0x9f, 0xc0, 0x8f, 0xc7, 0x8d, 0x66, 0x66, 0x67, 0xbb, 0x8b, 0x96, 0x42,
+	0xaf, 0x60, 0xf7, 0xf9, 0xff, 0x9e, 0xf7, 0x67, 0x0b, 0xb6, 0x3c, 0xca, 0x47, 0xd6, 0x78, 0x07,
+	0xbb, 0xe1, 0x08, 0xef, 0x58, 0x04, 0x0b, 0x1c, 0xba, 0xd8, 0xa7, 0x03, 0xe6, 0x73, 0xe6, 0x8c,
+	0x84, 0x19, 0x46, 0x81, 0x08, 0x20, 0x3c, 0x8b, 0x3d, 0x6c, 0x4a, 0xad, 0x99, 0x6a, 0x1b, 0xff,
+	0x3b, 0x41, 0xe0, 0xb8, 0xd4, 0x52, 0x8a, 0x61, 0x7c, 0x6a, 0x09, 0xe6, 0x51, 0x2e, 0xb0, 0x17,
+	0x26, 0x50, 0x63, 0x63, 0x8c, 0x5d, 0x46, 0xb0, 0xa0, 0x56, 0xfa, 0x4f, 0x62, 0x68, 0x5f, 0x14,
+	0xc1, 0x6a, 0x37, 0x8d, 0x74, 0x94, 0x04, 0x82, 0x2f, 0x41, 0x8d, 0xc7, 0x43, 0x6e, 0x47, 0x2c,
+	0x14, 0x2c, 0xf0, 0x79, 0xdd, 0x68, 0x15, 0xb7, 0x97, 0x1e, 0xdc, 0x35, 0xff, 0x0c, 0x6d, 0x76,
+	0x19, 0xb7, 0x83, 0x31, 0x8d, 0xce, 0x7b, 0x39, 0x02, 0x5d, 0xe5, 0xe1, 0x63, 0x50, 0xf2, 0xfa,
+	0xc7, 0xbd, 0x7a, 0xa1, 0x65, 0x5c, 0xeb, 0xe7, 0xb7, 0x24, 0xcc, 0x17, 0xfd, 0xe3, 0x1e, 0x52,
+	0x58, 0xe3, 0xa7, 0x01, 0x4a, 0xf2, 0x11, 0x9e, 0x80, 0xa6, 0x4d, 0x23, 0xc1, 0x4e, 0x99, 0x8d,
+	0x05, 0x1d, 0xd0, 0x4f, 0x21, 0x8b, 0xb0, 0x0c, 0x31, 0x90, 0x05, 0xd7, 0x0d, 0xe5, 0xbe, 0x61,
+	0x26, 0xdd, 0x30, 0xd3, 0x6e, 0x98, 0xfd, 0xb4, 0x1b, 0x68, 0x33, 0x87, 0x1f, 0x4e, 0x68, 0x69,
+	0x87, 0xef, 0xc0, 0x7f, 0x2e, 0xe6, 0x62, 0x90, 0x0f, 0x10, 0x51, 0x87, 0xfa, 0x34, 0x11, 0xe9,
+	0xe4, 0x67, 0x79, 0x6f, 0x4a, 0x07, 0x07, 0x19, 0x8f, 0x72, 0x38, 0xdc, 0x03, 0x9b, 0xd7, 0xb9,
+	0xe6, 0xf5, 0x62, 0xcb, 0xd8, 0xae, 0xa1, 0xba, 0x3d, 0x9d, 0xe5, 0xed, 0x6f, 0x45, 0xb0, 0x36,
+	0xb5, 0xd3, 0x70, 0x03, 0x14, 0x18, 0x51, 0x95, 0x57, 0x3b, 0x0b, 0x97, 0x9d, 0x52, 0x54, 0x58,
+	0x35, 0x50, 0x81, 0x11, 0xd8, 0x01, 0x9b, 0x76, 0xe0, 0x8b, 0x28, 0x70, 0x07, 0x93, 0x35, 0x12,
+	0xd8, 0xb7, 0xe9, 0x80, 0x11, 0x55, 0x4b, 0x4e, 0xbf, 0xae, 0x95, 0xaf, 0xf4, 0x00, 0x94, 0xee,
+	0x88, 0xc0, 0x67, 0x60, 0xd9, 0x0e, 0x7c, 0x9f, 0xda, 0x22, 0x69, 0x70, 0xf1, 0xa6, 0x16, 0x74,
+	0x16, 0x2f, 0x3b, 0xe5, 0x1f, 0x46, 0x61, 0xd1, 0x40, 0x4b, 0x9a, 0x54, 0xcd, 0x3d, 0x00, 0x7f,
+	0x11, 0x99, 0x7e, 0xce, 0x57, 0xe9, 0xc6, 0x76, 0xae, 0x64, 0x88, 0x72, 0xf2, 0x1a, 0x54, 0xb8,
+	0xc0, 0x22, 0xe6, 0xf5, 0xb2, 0x62, 0xad, 0x5b, 0xef, 0x63, 0x4f, 0x61, 0x2a, 0xb9, 0xaf, 0x86,
+	0x2c, 0x58, 0x3b, 0x82, 0xbb, 0x60, 0x61, 0x4c, 0x23, 0x2e, 0xc7, 0x5b, 0x51, 0x3e, 0x9b, 0xd3,
+	0x7c, 0xbe, 0x4d, 0x24, 0x28, 0xd5, 0xb6, 0xbf, 0x17, 0x41, 0x73, 0x46, 0x20, 0xd8, 0x05, 0xab,
+	0x6a, 0x97, 0xe2, 0x50, 0x9e, 0xda, 0x6d, 0x97, 0x73, 0x45, 0x32, 0x6f, 0x14, 0xa2, 0xea, 0xdd,
+	0x07, 0x65, 0x11, 0x08, 0xec, 0xce, 0x3c, 0x9b, 0x49, 0x16, 0x34, 0x1a, 0x33, 0x9b, 0xca, 0x04,
+	0x38, 0x4a, 0x38, 0xb8, 0x07, 0x8a, 0x36, 0xe1, 0x7a, 0x6a, 0x73, 0xe0, 0x92, 0x92, 0x30, 0x25,
+	0x5c, 0x8f, 0x69, 0x1e, 0x98, 0x26, 0xb0, 0x4b, 0xd2, 0x39, 0xcd, 0x03, 0xbb, 0x09, 0x1c, 0x11,
+	0xae, 0x07, 0x32, 0x0f, 0x1c, 0x11, 0xde, 0xbe, 0x30, 0xf2, 0x97, 0x92, 0x33, 0xc3, 0x2d, 0xb0,
+	0x12, 0x51, 0x1e, 0x06, 0x3e, 0xa7, 0x7c, 0xc0, 0xa9, 0x2f, 0xd4, 0x48, 0x4a, 0xa8, 0x36, 0x79,
+	0xdb, 0xa3, 0xbe, 0x80, 0xbb, 0x60, 0x3d, 0x93, 0x61, 0xfb, 0xcc, 0x0f, 0x3e, 0xba, 0x94, 0x38,
+	0x34, 0x39, 0x9a, 0x12, 0x5a, 0x9b, 0x58, 0x9f, 0xe6, 0x8c, 0xf0, 0x3e, 0x80, 0x19, 0x16, 0xd1,
+	0xf7, 0xd4, 0x16, 0x94, 0xa8, 0xd6, 0x97, 0xd0, 0xdf, 0x13, 0x0b, 0xd2, 0x86, 0xf6, 0x17, 0x03,
+	0x2c, 0xe8, 0xb5, 0x82, 0xfb, 0xa0, 0x4a, 0x42, 0xfd, 0xa0, 0xd7, 0xe4, 0xce, 0xb4, 0xaa, 0x9f,
+	0xc7, 0x1e, 0xee, 0xa6, 0x42, 0x94, 0x31, 0xf0, 0x11, 0x28, 0x53, 0x7f, 0x1c, 0x9c, 0xeb, 0x45,
+	0x69, 0x4d, 0x83, 0x0f, 0xa5, 0x20, 0x65, 0x13, 0x79, 0xfb, 0x33, 0xa8, 0x5d, 0xf1, 0x09, 0xeb,
+	0xd9, 0x39, 0xa8, 0x2f, 0xca, 0x64, 0xe3, 0xe1, 0x3a, 0xa8, 0x38, 0x4c, 0xf4, 0xb1, 0x93, 0x7c,
+	0x3a, 0x90, 0x7e, 0x82, 0xff, 0x82, 0xaa, 0xc3, 0xc4, 0x41, 0xe0, 0x79, 0x4c, 0xa8, 0x6a, 0xab,
+	0x28, 0x7b, 0x21, 0xad, 0xc3, 0x98, 0xb9, 0xa4, 0x8b, 0x45, 0x72, 0xf0, 0x55, 0x94, 0xbd, 0x68,
+	0x3f, 0x01, 0xcb, 0xf9, 0xac, 0x66, 0x44, 0xff, 0x07, 0x94, 0x15, 0xa6, 0x83, 0x27, 0x0f, 0x9d,
+	0x7b, 0x27, 0xdb, 0x0e, 0x13, 0xa3, 0x78, 0x68, 0xda, 0x81, 0x67, 0xc9, 0x9a, 0x47, 0x1f, 0xd4,
+	0x1f, 0x0b, 0x87, 0xcc, 0xba, 0xf2, 0x6b, 0x3a, 0xac, 0xa8, 0x7b, 0x7b, 0xf8, 0x2b, 0x00, 0x00,
+	0xff, 0xff, 0x0c, 0x82, 0x60, 0xb7, 0x65, 0x07, 0x00, 0x00,
 }
diff --git a/api/mesh/v1alpha1/dataplane_insight.proto b/api/mesh/v1alpha1/dataplane_insight.proto
index 02df0e2c9..90b7f3765 100644
--- a/api/mesh/v1alpha1/dataplane_insight.proto
+++ b/api/mesh/v1alpha1/dataplane_insight.proto
@@ -57,6 +57,9 @@ message DiscoverySubscription {
   // Status of the ADS subscription.
   DiscoverySubscriptionStatus status = 5
       [ (validate.rules).message.required = true ];
+
+  // Version of Envoy and Kuma dataplane
+  Version version = 6;
 }
 
 // DiscoverySubscriptionStatus defines status of an ADS subscription.
@@ -93,3 +96,39 @@ message DiscoveryServiceStats {
   // Number of xDS responses NACKed by the Dataplane.
   uint64 responses_rejected = 3;
 }
+
+// Version defines version of Kuma Dataplane and Envoy
+message Version {
+
+  // Version of Kuma Dataplane
+  KumaDpVersion dpVersion = 1;
+
+  // Version of Envoy
+  EnvoyVersion envoy = 2;
+}
+
+// KumaDpVersion describes details of Kuma Dataplane version
+message KumaDpVersion {
+
+  // Version number of Kuma Dataplane
+  string version = 1;
+
+  // Git tag of Kuma Dataplane version
+  string gitTag = 2;
+
+  // Git commit of Kuma Dataplane version
+  string gitCommit = 3;
+
+  // Build date of Kuma Dataplane version
+  string buildDate = 4;
+}
+
+// EnvoyVersion describes details of Envoy version
+message EnvoyVersion {
+
+  // Version number of Envoy
+  string version = 1;
+
+  // Full build tag of Envoy version
+  string build = 2;
+}
diff --git a/api/mesh/v1alpha1/dataplane_insight_helpers.go b/api/mesh/v1alpha1/dataplane_insight_helpers.go
index e3431830e..47f093aec 100644
--- a/api/mesh/v1alpha1/dataplane_insight_helpers.go
+++ b/api/mesh/v1alpha1/dataplane_insight_helpers.go
@@ -17,6 +17,21 @@ func NewSubscriptionStatus() *DiscoverySubscriptionStatus {
 	}
 }
 
+func NewVersion() *Version {
+	return &Version{
+		DpVersion: &KumaDpVersion{
+			Version:   "",
+			GitTag:    "",
+			GitCommit: "",
+			BuildDate: "",
+		},
+		Envoy: &EnvoyVersion{
+			Version: "",
+			Build:   "",
+		},
+	}
+}
+
 func (ds *DataplaneInsight) IsOnline() bool {
 	for _, s := range ds.GetSubscriptions() {
 		if s.ConnectTime != nil && s.DisconnectTime == nil {
diff --git a/app/kuma-dp/pkg/dataplane/envoy/envoy.go b/app/kuma-dp/pkg/dataplane/envoy/envoy.go
index bf4fabb2a..af2bf4d5b 100644
--- a/app/kuma-dp/pkg/dataplane/envoy/envoy.go
+++ b/app/kuma-dp/pkg/dataplane/envoy/envoy.go
@@ -7,6 +7,8 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
+	"strings"
 	"time"
 
 	"github.com/kumahq/kuma/pkg/core/resources/model/rest"
@@ -23,7 +25,7 @@ var (
 	runLog = core.Log.WithName("kuma-dp").WithName("run").WithName("envoy")
 )
 
-type BootstrapConfigFactoryFunc func(url string, cfg kuma_dp.Config, dp *rest.Resource) (proto.Message, error)
+type BootstrapConfigFactoryFunc func(url string, cfg kuma_dp.Config, dp *rest.Resource, ev EnvoyVersion) (proto.Message, error)
 
 type Opts struct {
 	Config    kuma_dp.Config
@@ -47,6 +49,11 @@ type Envoy struct {
 	opts Opts
 }
 
+type EnvoyVersion struct {
+	Build   string
+	Version string
+}
+
 func (e *Envoy) NeedLeaderElection() bool {
 	return false
 }
@@ -95,8 +102,13 @@ func lookupEnvoyPath(configuredPath string) (string, error) {
 }
 
 func (e *Envoy) Start(stop <-chan struct{}) error {
+	envoyVersion, err := e.version()
+	if err != nil {
+		return errors.Wrap(err, "failed to get Envoy version")
+	}
+	runLog.Info("fetched Envoy version", "version", envoyVersion)
 	runLog.Info("generating bootstrap configuration")
-	bootstrapConfig, err := e.opts.Generator(e.opts.Config.ControlPlane.URL, e.opts.Config, e.opts.Dataplane)
+	bootstrapConfig, err := e.opts.Generator(e.opts.Config.ControlPlane.URL, e.opts.Config, e.opts.Dataplane, *envoyVersion)
 	if err != nil {
 		return errors.Errorf("Failed to generate Envoy bootstrap config. %v", err)
 	}
@@ -156,3 +168,27 @@ func (e *Envoy) Start(stop <-chan struct{}) error {
 		return err
 	}
 }
+
+func (e *Envoy) version() (*EnvoyVersion, error) {
+	binaryPathConfig := e.opts.Config.DataplaneRuntime.BinaryPath
+	resolvedPath, err := lookupEnvoyPath(binaryPathConfig)
+	if err != nil {
+		return nil, err
+	}
+	arg := "--version"
+	command := exec.Command(resolvedPath, arg)
+	output, err := command.Output()
+	if err != nil {
+		return nil, errors.Wrap(err, fmt.Sprintf("the envoy excutable was found at %s but an error occurred when executing it with arg %s", resolvedPath, arg))
+	}
+	build := strings.Trim(string(output), "\n")
+	build = regexp.MustCompile(`:(.*)`).FindString(build)
+	build = strings.Trim(build, ":")
+	build = strings.Trim(build, " ")
+	version := regexp.MustCompile(`/([0-9.]+)/`).FindString(build)
+	version = strings.Trim(version, "/")
+	return &EnvoyVersion{
+		Build:   build,
+		Version: version,
+	}, nil
+}
diff --git a/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap.go b/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap.go
index 29562f599..087857efd 100644
--- a/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap.go
+++ b/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap.go
@@ -23,6 +23,7 @@ import (
 	"github.com/kumahq/kuma/pkg/core"
 	rest_types "github.com/kumahq/kuma/pkg/core/resources/model/rest"
 	util_proto "github.com/kumahq/kuma/pkg/util/proto"
+	kuma_version "github.com/kumahq/kuma/pkg/version"
 	"github.com/kumahq/kuma/pkg/xds/bootstrap/types"
 )
 
@@ -48,7 +49,7 @@ func IsInvalidRequestErr(err error) bool {
 	return strings.HasPrefix(err.Error(), "Invalid request: ")
 }
 
-func (b *remoteBootstrap) Generate(url string, cfg kuma_dp.Config, dp *rest_types.Resource) (proto.Message, error) {
+func (b *remoteBootstrap) Generate(url string, cfg kuma_dp.Config, dp *rest_types.Resource, ev EnvoyVersion) (proto.Message, error) {
 	bootstrapUrl, err := net_url.Parse(url)
 	if err != nil {
 		return nil, err
@@ -78,7 +79,7 @@ func (b *remoteBootstrap) Generate(url string, cfg kuma_dp.Config, dp *rest_type
 	var respBytes []byte
 	err = retry.Do(context.Background(), backoff, func(ctx context.Context) error {
 		log.Info("trying to fetch bootstrap configuration from the Control Plane")
-		respBytes, err = b.requestForBootstrap(bootstrapUrl, cfg, dp)
+		respBytes, err = b.requestForBootstrap(bootstrapUrl, cfg, dp, ev)
 		if err == nil {
 			return nil
 		}
@@ -105,7 +106,7 @@ func (b *remoteBootstrap) Generate(url string, cfg kuma_dp.Config, dp *rest_type
 	return &bootstrap, nil
 }
 
-func (b *remoteBootstrap) requestForBootstrap(url *net_url.URL, cfg kuma_dp.Config, dp *rest_types.Resource) ([]byte, error) {
+func (b *remoteBootstrap) requestForBootstrap(url *net_url.URL, cfg kuma_dp.Config, dp *rest_types.Resource, ev EnvoyVersion) ([]byte, error) {
 	url.Path = "/bootstrap"
 	var dataplaneResource string
 	if dp != nil {
@@ -123,6 +124,18 @@ func (b *remoteBootstrap) requestForBootstrap(url *net_url.URL, cfg kuma_dp.Conf
 		AdminPort:          cfg.Dataplane.AdminPort.Lowest(),
 		DataplaneTokenPath: cfg.DataplaneRuntime.TokenPath,
 		DataplaneResource:  dataplaneResource,
+		Version: types.Version{
+			KumaDp: types.KumaDpVersion{
+				Version:   kuma_version.Build.Version,
+				GitTag:    kuma_version.Build.GitTag,
+				GitCommit: kuma_version.Build.GitCommit,
+				BuildDate: kuma_version.Build.BuildDate,
+			},
+			Envoy: types.EnvoyVersion{
+				Version: ev.Version,
+				Build:   ev.Build,
+			},
+		},
 	}
 	jsonBytes, err := json.Marshal(request)
 	if err != nil {
diff --git a/pkg/xds/bootstrap/generator.go b/pkg/xds/bootstrap/generator.go
index 43c2fa94e..31a3afe5c 100644
--- a/pkg/xds/bootstrap/generator.go
+++ b/pkg/xds/bootstrap/generator.go
@@ -197,6 +197,12 @@ func (b *bootstrapGenerator) generateFor(proxyId core_xds.ProxyId, dataplane *co
 		DataplaneTokenPath: request.DataplaneTokenPath,
 		DataplaneResource:  request.DataplaneResource,
 		CertBytes:          certBytes,
+		KumaDpVersion:      request.Version.KumaDp.Version,
+		KumaDpGitTag:       request.Version.KumaDp.GitTag,
+		KumaDpGitCommit:    request.Version.KumaDp.GitCommit,
+		KumaDpBuildDate:    request.Version.KumaDp.BuildDate,
+		EnvoyVersion:       request.Version.Envoy.Version,
+		EnvoyBuild:         request.Version.Envoy.Build,
 	}
 	log.WithValues("params", params).Info("Generating bootstrap config")
 	return b.configForParameters(params)
diff --git a/pkg/xds/bootstrap/template.go b/pkg/xds/bootstrap/template.go
index 946b559dd..a4da6ff7f 100644
--- a/pkg/xds/bootstrap/template.go
+++ b/pkg/xds/bootstrap/template.go
@@ -15,6 +15,12 @@ type configParameters struct {
 	DataplaneTokenPath string
 	DataplaneResource  string
 	CertBytes          string
+	KumaDpVersion      string
+	KumaDpGitTag       string
+	KumaDpGitCommit    string
+	KumaDpBuildDate    string
+	EnvoyVersion       string
+	EnvoyBuild         string
 }
 
 const configTemplate string = `
@@ -31,6 +37,15 @@ node:
 {{if .AdminPort }}
     dataplane.admin.port: "{{ .AdminPort }}"
 {{ end }}
+    version:
+      kumaDp:
+        version: "{{ .KumaDpVersion }}"
+        gitTag: "{{ .KumaDpGitTag }}"
+        gitCommit: "{{ .KumaDpGitCommit }}"
+        buildDate: "{{ .KumaDpBuildDate }}"
+      envoy:
+        version: "{{ .EnvoyVersion }}"
+        build: "{{ .EnvoyBuild }}"
 
 {{if .AdminPort }}
 admin:
diff --git a/pkg/xds/bootstrap/types/bootstrap_request.go b/pkg/xds/bootstrap/types/bootstrap_request.go
index a1829f98b..c3d326a18 100644
--- a/pkg/xds/bootstrap/types/bootstrap_request.go
+++ b/pkg/xds/bootstrap/types/bootstrap_request.go
@@ -1,10 +1,28 @@
 package types
 
 type BootstrapRequest struct {
-	Mesh               string `json:"mesh"`
-	Name               string `json:"name"`
-	AdminPort          uint32 `json:"adminPort,omitempty"`
-	DataplaneTokenPath string `json:"dataplaneTokenPath,omitempty"`
-	DataplaneResource  string `json:"dataplaneResource,omitempty"`
-	Host               string `json:"-"`
+	Mesh               string  `json:"mesh"`
+	Name               string  `json:"name"`
+	AdminPort          uint32  `json:"adminPort,omitempty"`
+	DataplaneTokenPath string  `json:"dataplaneTokenPath,omitempty"`
+	DataplaneResource  string  `json:"dataplaneResource,omitempty"`
+	Host               string  `json:"-"`
+	Version            Version `json:"version"`
+}
+
+type Version struct {
+	KumaDp KumaDpVersion `json:"kumaDp"`
+	Envoy  EnvoyVersion  `json:"envoy"`
+}
+
+type KumaDpVersion struct {
+	Version   string `json:"version"`
+	GitTag    string `json:"gitTag"`
+	GitCommit string `json:"gitCommit"`
+	BuildDate string `json:"buildDate"`
+}
+
+type EnvoyVersion struct {
+	Version string `json:"version"`
+	Build   string `json:"build"`
 }
diff --git a/pkg/xds/server/dataplane_status_tracker.go b/pkg/xds/server/dataplane_status_tracker.go
index c3af7ed7f..ba5867fa4 100644
--- a/pkg/xds/server/dataplane_status_tracker.go
+++ b/pkg/xds/server/dataplane_status_tracker.go
@@ -5,6 +5,8 @@ import (
 	"sync"
 	"time"
 
+	pstruct "github.com/golang/protobuf/ptypes/struct"
+
 	envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
 	envoy_xds "github.com/envoyproxy/go-control-plane/pkg/server/v2"
 	"github.com/golang/protobuf/proto"
@@ -71,6 +73,7 @@ func (c *dataplaneStatusTracker) OnStreamOpen(ctx context.Context, streamID int6
 		ControlPlaneInstanceId: c.runtimeInfo.GetInstanceId(),
 		ConnectTime:            util_proto.MustTimestampProto(now()),
 		Status:                 mesh_proto.NewSubscriptionStatus(),
+		Version:                mesh_proto.NewVersion(),
 	}
 	// initialize state per ADS stream
 	state := &streamState{
@@ -120,6 +123,9 @@ func (c *dataplaneStatusTracker) OnStreamRequest(streamID int64, req *envoy.Disc
 	if state.dataplaneId == (core_model.ResourceKey{}) {
 		if id, err := core_xds.ParseProxyId(req.Node); err == nil {
 			state.dataplaneId = core_model.ResourceKey{Mesh: id.Mesh, Name: id.Name}
+			if err := readVersion(req.Node.Metadata, state.subscription.Version); err != nil {
+				xdsServerLog.Error(err, "failed to extract version out of the Envoy metadata", "streamid", streamID, "metadata", req.Node.Metadata)
+			}
 			// kick off async Dataplane status flusher
 			go c.createStatusSink(state).Start(state.stop)
 		} else {
@@ -188,3 +194,14 @@ func (s *streamState) GetStatus() (core_model.ResourceKey, *mesh_proto.Discovery
 func (s *streamState) Close() {
 	close(s.stop)
 }
+
+func readVersion(metadata *pstruct.Struct, version *mesh_proto.Version) error {
+	rawVersion := metadata.Fields["version"].GetStructValue()
+	if rawVersion != nil {
+		err := util_proto.ToTyped(rawVersion, version)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}


Test patch:
diff --git a/app/kuma-dp/cmd/run_test.go b/app/kuma-dp/cmd/run_test.go
index 75098fccf..cb9a54e28 100644
--- a/app/kuma-dp/cmd/run_test.go
+++ b/app/kuma-dp/cmd/run_test.go
@@ -36,7 +36,7 @@ var _ = Describe("run", func() {
 	BeforeEach(func() {
 		backupSetupSignalHandler = core.SetupSignalHandler
 		backupBootstrapGenerator = bootstrapGenerator
-		bootstrapGenerator = func(_ string, cfg kumadp.Config, _ *rest.Resource) (proto.Message, error) {
+		bootstrapGenerator = func(_ string, cfg kumadp.Config, _ *rest.Resource, version envoy.EnvoyVersion) (proto.Message, error) {
 			bootstrap := envoy_bootstrap.Bootstrap{}
 			respBytes, err := ioutil.ReadFile(filepath.Join("testdata", "bootstrap-config.golden.yaml"))
 			Expect(err).ToNot(HaveOccurred())
@@ -152,13 +152,14 @@ var _ = Describe("run", func() {
 			Expect(err).ToNot(HaveOccurred())
 			// and
 			actualArgs := strings.Split(string(cmdline), "\n")
-			Expect(actualArgs[0]).To(Equal("-c"))
-			actualConfigFile := actualArgs[1]
+			Expect(actualArgs[0]).To(Equal("--version"))
+			Expect(actualArgs[1]).To(Equal("-c"))
+			actualConfigFile := actualArgs[2]
 			Expect(actualConfigFile).To(BeARegularFile())
 
 			// then
 			if given.expectedFile != "" {
-				Expect(actualArgs[1]).To(Equal(given.expectedFile))
+				Expect(actualArgs[2]).To(Equal(given.expectedFile))
 			}
 
 			// when
diff --git a/app/kuma-dp/cmd/testdata/envoy-mock.sleep.sh b/app/kuma-dp/cmd/testdata/envoy-mock.sleep.sh
index eca65192c..208bf00b7 100755
--- a/app/kuma-dp/cmd/testdata/envoy-mock.sleep.sh
+++ b/app/kuma-dp/cmd/testdata/envoy-mock.sleep.sh
@@ -1,9 +1,19 @@
 #!/bin/sh
 
-touch ${ENVOY_MOCK_CMDLINE_FILE}
-for arg in "$@"; do
-    echo $arg >> ${ENVOY_MOCK_CMDLINE_FILE}
-done
+if [ ! -e ${ENVOY_MOCK_CMDLINE_FILE} ]; then
+    touch ${ENVOY_MOCK_CMDLINE_FILE}
+fi
+
+if [ "$1" = "--version" ];
+then
+    echo $1 >> ${ENVOY_MOCK_CMDLINE_FILE}
+    printf "\n50ef0945fa2c5da4bff7627c3abf41fdd3b7cffd/1.15.0/clean-getenvoy-2aa564b-envoy/RELEASE/BoringSSL\n"
+    exit 0
+else
+    for arg in "$@"; do
+        echo $arg >> ${ENVOY_MOCK_CMDLINE_FILE}
+    done
+fi
 
 echo $$ >${ENVOY_MOCK_PID_FILE}
 
diff --git a/app/kuma-dp/pkg/dataplane/envoy/envoy_test.go b/app/kuma-dp/pkg/dataplane/envoy/envoy_test.go
index a5b68d047..f48d4af5f 100644
--- a/app/kuma-dp/pkg/dataplane/envoy/envoy_test.go
+++ b/app/kuma-dp/pkg/dataplane/envoy/envoy_test.go
@@ -73,7 +73,7 @@ var _ = Describe("Envoy", func() {
 					ConfigDir:  configDir,
 				},
 			}
-			sampleConfig := func(string, kuma_dp.Config, *rest.Resource) (proto.Message, error) {
+			sampleConfig := func(string, kuma_dp.Config, *rest.Resource, EnvoyVersion) (proto.Message, error) {
 				return &envoy_bootstrap.Bootstrap{
 					Node: &envoy_core.Node{
 						Id: "example",
@@ -144,7 +144,7 @@ var _ = Describe("Envoy", func() {
 					ConfigDir:  configDir,
 				},
 			}
-			sampleConfig := func(string, kuma_dp.Config, *rest.Resource) (proto.Message, error) {
+			sampleConfig := func(string, kuma_dp.Config, *rest.Resource, EnvoyVersion) (proto.Message, error) {
 				return &envoy_bootstrap.Bootstrap{}, nil
 			}
 
@@ -186,7 +186,7 @@ var _ = Describe("Envoy", func() {
 					ConfigDir:  configDir,
 				},
 			}
-			sampleConfig := func(string, kuma_dp.Config, *rest.Resource) (proto.Message, error) {
+			sampleConfig := func(string, kuma_dp.Config, *rest.Resource, EnvoyVersion) (proto.Message, error) {
 				return &envoy_bootstrap.Bootstrap{}, nil
 			}
 
@@ -207,4 +207,30 @@ var _ = Describe("Envoy", func() {
 			close(done)
 		}, 10)
 	})
+
+	Describe("Parse version", func() {
+		It("should properly read envoy version", func() {
+			// given
+			cfg := kuma_dp.Config{
+				DataplaneRuntime: kuma_dp.DataplaneRuntime{
+					BinaryPath: filepath.Join("testdata", "envoy-mock.exit-0.sh"),
+					ConfigDir:  configDir,
+				},
+			}
+
+			// when
+			dataplane, err := New(Opts{
+				Config: cfg,
+				Stdout: &bytes.Buffer{},
+				Stderr: &bytes.Buffer{},
+			})
+			Expect(err).ToNot(HaveOccurred())
+			version, err := dataplane.version()
+
+			// then
+			Expect(err).ToNot(HaveOccurred())
+			Expect(version.Version).To(Equal("1.15.0"))
+			Expect(version.Build).To(Equal("50ef0945fa2c5da4bff7627c3abf41fdd3b7cffd/1.15.0/clean-getenvoy-2aa564b-envoy/RELEASE/BoringSSL"))
+		})
+	})
 })
diff --git a/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap_test.go b/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap_test.go
index 1c9cbbd9b..065150c98 100644
--- a/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap_test.go
+++ b/app/kuma-dp/pkg/dataplane/envoy/remote_bootstrap_test.go
@@ -10,6 +10,8 @@ import (
 	"strings"
 	"time"
 
+	kuma_version "github.com/kumahq/kuma/pkg/version"
+
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -28,6 +30,15 @@ var _ = Describe("Remote Bootstrap", func() {
 		expectedBootstrapRequest string
 	}
 
+	BeforeEach(func() {
+		kuma_version.Build = kuma_version.BuildInfo{
+			Version:   "0.0.1",
+			GitTag:    "v0.0.1",
+			GitCommit: "91ce236824a9d875601679aa80c63783fb0e8725",
+			BuildDate: "2019-08-07T11:26:06Z",
+		}
+	})
+
 	DescribeTable("should generate bootstrap configuration", func(given testCase) {
 		// given
 		mux := http.NewServeMux()
@@ -51,7 +62,10 @@ var _ = Describe("Remote Bootstrap", func() {
 		generator := NewRemoteBootstrapGenerator(http.DefaultClient)
 
 		// when
-		config, err := generator(fmt.Sprintf("http://localhost:%d", port), given.config, given.dataplane)
+		config, err := generator(fmt.Sprintf("http://localhost:%d", port), given.config, given.dataplane, EnvoyVersion{
+			Build:   "hash/1.15.0/RELEASE",
+			Version: "1.15.0",
+		})
 
 		// then
 		Expect(err).ToNot(HaveOccurred())
@@ -75,14 +89,25 @@ var _ = Describe("Remote Bootstrap", func() {
 						},
 					},
 					expectedBootstrapRequest: `
-                    {
-                      "mesh": "demo",
-                      "name": "sample",
-                      "adminPort": 4321,
-                      "dataplaneTokenPath": "/tmp/token",
-                      "dataplaneResource": "{\"type\":\"Dataplane\",\"mesh\":\"demo\",\"name\":\"sample\",\"creationTime\":\"0001-01-01T00:00:00Z\",\"modificationTime\":\"0001-01-01T00:00:00Z\"}"
-                    }
-`,
+					{
+					  "mesh": "demo",
+					  "name": "sample",
+					  "adminPort": 4321,
+					  "dataplaneTokenPath": "/tmp/token",
+					  "dataplaneResource": "{\"type\":\"Dataplane\",\"mesh\":\"demo\",\"name\":\"sample\",\"creationTime\":\"0001-01-01T00:00:00Z\",\"modificationTime\":\"0001-01-01T00:00:00Z\"}",
+					  "version": {
+						"kumaDp": {
+						  "version": "0.0.1",
+						  "gitTag": "v0.0.1",
+						  "gitCommit": "91ce236824a9d875601679aa80c63783fb0e8725",
+						  "buildDate": "2019-08-07T11:26:06Z"
+						},
+						"envoy": {
+						  "version": "1.15.0",
+						  "build": "hash/1.15.0/RELEASE"
+						}
+					  }
+					}`,
 				}
 			}()),
 
@@ -109,9 +134,20 @@ var _ = Describe("Remote Bootstrap", func() {
                       "name": "sample",
                       "adminPort": 4321,
                       "dataplaneTokenPath": "/tmp/token",
-                      "dataplaneResource": "{\"type\":\"Dataplane\",\"mesh\":\"demo\",\"name\":\"sample\",\"creationTime\":\"0001-01-01T00:00:00Z\",\"modificationTime\":\"0001-01-01T00:00:00Z\"}"
-                    }
-`,
+                      "dataplaneResource": "{\"type\":\"Dataplane\",\"mesh\":\"demo\",\"name\":\"sample\",\"creationTime\":\"0001-01-01T00:00:00Z\",\"modificationTime\":\"0001-01-01T00:00:00Z\"}",
+                      "version": {
+                        "kumaDp": {
+                          "version": "0.0.1",
+                          "gitTag": "v0.0.1",
+                          "gitCommit": "91ce236824a9d875601679aa80c63783fb0e8725",
+                          "buildDate": "2019-08-07T11:26:06Z"
+                        },
+                        "envoy": {
+                          "version": "1.15.0",
+                          "build": "hash/1.15.0/RELEASE"
+                        }
+                      }
+                    }`,
 				}
 			}()),
 		Entry("should support empty port range",
@@ -136,9 +172,20 @@ var _ = Describe("Remote Bootstrap", func() {
                       "mesh": "demo",
                       "name": "sample",
                       "dataplaneTokenPath": "/tmp/token",
-                      "dataplaneResource": "{\"type\":\"Dataplane\",\"mesh\":\"demo\",\"name\":\"sample\",\"creationTime\":\"0001-01-01T00:00:00Z\",\"modificationTime\":\"0001-01-01T00:00:00Z\"}"
-                    }
-`,
+                      "dataplaneResource": "{\"type\":\"Dataplane\",\"mesh\":\"demo\",\"name\":\"sample\",\"creationTime\":\"0001-01-01T00:00:00Z\",\"modificationTime\":\"0001-01-01T00:00:00Z\"}",
+                      "version": {
+                        "kumaDp": {
+                          "version": "0.0.1",
+                          "gitTag": "v0.0.1",
+                          "gitCommit": "91ce236824a9d875601679aa80c63783fb0e8725",
+                          "buildDate": "2019-08-07T11:26:06Z"
+                        },
+                        "envoy": {
+                          "version": "1.15.0",
+                          "build": "hash/1.15.0/RELEASE"
+                        }
+                      }
+                    }`,
 				}
 			}()),
 	)
@@ -176,7 +223,7 @@ var _ = Describe("Remote Bootstrap", func() {
 				Mesh: "default",
 				Name: "dp-1",
 			},
-		})
+		}, EnvoyVersion{})
 
 		// then
 		Expect(err).ToNot(HaveOccurred())
@@ -204,7 +251,7 @@ var _ = Describe("Remote Bootstrap", func() {
 		config.ControlPlane.Retry.MaxDuration = 100 * time.Millisecond
 		_, err = generator(fmt.Sprintf("http://localhost:%d", port), config, &rest.Resource{
 			Meta: rest.ResourceMeta{Mesh: "default", Name: "dp-1"},
-		})
+		}, EnvoyVersion{})
 
 		// then
 		Expect(err).To(MatchError("retryable: Dataplane entity not found. If you are running on Universal please create a Dataplane entity on kuma-cp before starting kuma-dp. If you are running on Kubernetes, please check the kuma-cp logs to determine why the Dataplane entity could not be created by the automatic sidecar injection."))
diff --git a/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-0.sh b/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-0.sh
index 238f1bd8d..52a969318 100755
--- a/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-0.sh
+++ b/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-0.sh
@@ -1,4 +1,10 @@
 #!/bin/sh
 
+if [ "$1" = "--version" ];
+then
+  printf "\nenvoy  version: 50ef0945fa2c5da4bff7627c3abf41fdd3b7cffd/1.15.0/clean-getenvoy-2aa564b-envoy/RELEASE/BoringSSL\n\n"
+  exit 0
+fi
+
 # print arguments to verify in the test
 echo $@
diff --git a/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-1.sh b/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-1.sh
index ed6febbe9..bf21a5259 100755
--- a/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-1.sh
+++ b/app/kuma-dp/pkg/dataplane/envoy/testdata/envoy-mock.exit-1.sh
@@ -1,5 +1,11 @@
 #!/bin/sh
 
+if [ "$1" = "--version" ];
+then
+  printf "\nenvoy  version: 50ef0945fa2c5da4bff7627c3abf41fdd3b7cffd/1.15.0/clean-getenvoy-2aa564b-envoy/RELEASE/BoringSSL\n\n"
+  exit 0
+fi
+
 >&2 echo Envoy crashed
 
 # simulate crash of Envoy process
diff --git a/pkg/xds/bootstrap/generator_test.go b/pkg/xds/bootstrap/generator_test.go
index e1736d81b..78eb4eacc 100644
--- a/pkg/xds/bootstrap/generator_test.go
+++ b/pkg/xds/bootstrap/generator_test.go
@@ -29,6 +29,19 @@ var _ = Describe("bootstrapGenerator", func() {
 
 	var resManager core_manager.ResourceManager
 
+	defaultVersion := types.Version{
+		KumaDp: types.KumaDpVersion{
+			Version:   "0.0.1",
+			GitTag:    "v0.0.1",
+			GitCommit: "91ce236824a9d875601679aa80c63783fb0e8725",
+			BuildDate: "2019-08-07T11:26:06Z",
+		},
+		Envoy: types.EnvoyVersion{
+			Build:   "hash/1.15.0/RELEASE",
+			Version: "1.15.0",
+		},
+	}
+
 	BeforeEach(func() {
 		resManager = core_manager.NewResourceManager(memory.NewStore())
 		core.Now = func() time.Time {
@@ -107,8 +120,9 @@ var _ = Describe("bootstrapGenerator", func() {
 				return cfg
 			},
 			request: types.BootstrapRequest{
-				Mesh: "mesh",
-				Name: "name.namespace",
+				Mesh:    "mesh",
+				Name:    "name.namespace",
+				Version: defaultVersion,
 			},
 			expectedConfigFile: "generator.default-config-minimal-request.golden.yaml",
 		}),
@@ -125,6 +139,7 @@ var _ = Describe("bootstrapGenerator", func() {
 				Name:               "name.namespace",
 				AdminPort:          1234,
 				DataplaneTokenPath: "/tmp/token",
+				Version:            defaultVersion,
 			},
 			expectedConfigFile: "generator.default-config.golden.yaml",
 		}),
@@ -141,8 +156,9 @@ var _ = Describe("bootstrapGenerator", func() {
 				}
 			},
 			request: types.BootstrapRequest{
-				Mesh: "mesh",
-				Name: "name.namespace",
+				Mesh:    "mesh",
+				Name:    "name.namespace",
+				Version: defaultVersion,
 			},
 			expectedConfigFile: "generator.custom-config-minimal-request.golden.yaml",
 		}),
@@ -184,6 +200,7 @@ var _ = Describe("bootstrapGenerator", func() {
     ]
   }
 }`,
+				Version: defaultVersion,
 			},
 			expectedConfigFile: "generator.custom-config.golden.yaml",
 		}),
diff --git a/pkg/xds/bootstrap/server_test.go b/pkg/xds/bootstrap/server_test.go
index 9b83b885d..f766f86fd 100644
--- a/pkg/xds/bootstrap/server_test.go
+++ b/pkg/xds/bootstrap/server_test.go
@@ -3,6 +3,7 @@ package bootstrap_test
 import (
 	"context"
 	"crypto/tls"
+	"fmt"
 	"io/ioutil"
 	"net/http"
 	"path/filepath"
@@ -38,6 +39,20 @@ var _ = Describe("Bootstrap Server", func() {
 	var baseUrl string
 	var metrics core_metrics.Metrics
 
+	version := `
+	"version": {
+	  "kumaDp": {
+	    "version": "0.0.1",
+	    "gitTag": "v0.0.1",
+	    "gitCommit": "91ce236824a9d875601679aa80c63783fb0e8725",
+	    "buildDate": "2019-08-07T11:26:06Z"
+	  },
+	  "envoy": {
+	    "version": "1.15.0",
+	    "build": "hash/1.15.0/RELEASE"
+	  }
+	}`
+
 	httpClient := &http.Client{
 		Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
 	}
@@ -142,17 +157,17 @@ var _ = Describe("Bootstrap Server", func() {
 		},
 		Entry("minimal data provided (universal)", testCase{
 			dataplaneName:      "dp-1",
-			body:               `{ "mesh": "default", "name": "dp-1", "dataplaneTokenPath": "/tmp/token" }`,
+			body:               fmt.Sprintf(`{ "mesh": "default", "name": "dp-1", "dataplaneTokenPath": "/tmp/token", %s }`, version),
 			expectedConfigFile: "bootstrap.universal.golden.yaml",
 		}),
 		Entry("minimal data provided (k8s)", testCase{
 			dataplaneName:      "dp-1.default",
-			body:               `{ "mesh": "default", "name": "dp-1.default", "dataplaneTokenPath": "/tmp/token" }`,
+			body:               fmt.Sprintf(`{ "mesh": "default", "name": "dp-1.default", "dataplaneTokenPath": "/tmp/token", %s }`, version),
 			expectedConfigFile: "bootstrap.k8s.golden.yaml",
 		}),
 		Entry("full data provided", testCase{
 			dataplaneName:      "dp-1.default",
-			body:               `{ "mesh": "default", "name": "dp-1.default", "adminPort": 1234, "dataplaneTokenPath": "/tmp/token" }`,
+			body:               fmt.Sprintf(`{ "mesh": "default", "name": "dp-1.default", "adminPort": 1234, "dataplaneTokenPath": "/tmp/token", %s }`, version),
 			expectedConfigFile: "bootstrap.overridden.golden.yaml",
 		}),
 	)
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
index 64414a480..da6dfcc34 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
@@ -26,6 +26,15 @@ node:
   id: default.dp-1.default
   metadata:
     dataplaneTokenPath: /tmp/token
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 1s
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
index a1202c8f8..81c676046 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
@@ -33,6 +33,15 @@ node:
   metadata:
     dataplane.admin.port: "1234"
     dataplaneTokenPath: /tmp/token
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 1s
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
index e7e788e80..83c8fe19d 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
@@ -26,6 +26,15 @@ node:
   id: default.dp-1
   metadata:
     dataplaneTokenPath: /tmp/token
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 1s
diff --git a/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml b/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml
index b3864710d..7dc9299c6 100644
--- a/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml
@@ -24,6 +24,15 @@ node:
   id: mesh.name.namespace
   metadata:
     dataplane.admin.port: "9902"
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 2s
diff --git a/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml b/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
index 297b0f883..42c37570b 100644
--- a/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
@@ -34,6 +34,15 @@ node:
     dataplane.admin.port: "1234"
     dataplane.resource: ' { "type": "Dataplane", "mesh": "mesh", "name": "name.namespace", "creationTime": "1970-01-01T00:00:00Z", "modificationTime": "1970-01-01T00:00:00Z", "networking": { "address": "127.0.0.1", "inbound": [ { "port": 22022, "servicePort": 8443, "tags": { "kuma.io/protocol": "http2", "kuma.io/service": "backend" } }, ] } }'
     dataplaneTokenPath: /tmp/token
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 2s
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml
index 61064d539..5395f3bfe 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml
@@ -16,6 +16,16 @@ dynamicResources:
 node:
   cluster: backend
   id: mesh.name.namespace
+  metadata:
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 1s
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
index c1e4ccbde..23ab19ef6 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
@@ -33,6 +33,15 @@ node:
   metadata:
     dataplane.admin.port: "1234"
     dataplaneTokenPath: /tmp/token
+    version:
+      kumaDp:
+        version: 0.0.1
+        gitTag: v0.0.1
+        gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+        buildDate: 2019-08-07T11:26:06Z
+      envoy:
+        version: 1.15.0
+        build: hash/1.15.0/RELEASE
 staticResources:
   clusters:
     - connectTimeout: 1s
diff --git a/pkg/xds/server/dataplane_status_tracker_test.go b/pkg/xds/server/dataplane_status_tracker_test.go
index 370b40ebe..e5350ca79 100644
--- a/pkg/xds/server/dataplane_status_tracker_test.go
+++ b/pkg/xds/server/dataplane_status_tracker_test.go
@@ -4,6 +4,10 @@ import (
 	"context"
 	"time"
 
+	pstruct "github.com/golang/protobuf/ptypes/struct"
+
+	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
+
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -89,6 +93,9 @@ var _ = Describe("DataplaneStatusTracker", func() {
               lds: {}
               rds: {}
               total: {}
+            version:
+              dpVersion: {}
+              envoy: {}
 `))
 
 		By("simulating end of ADS subscription")
@@ -111,6 +118,9 @@ var _ = Describe("DataplaneStatusTracker", func() {
               lds: {}
               rds: {}
               total: {}
+            version:
+              dpVersion: {}
+              envoy: {}
 `))
 	})
 
@@ -153,6 +163,9 @@ var _ = Describe("DataplaneStatusTracker", func() {
           lds: {}
           rds: {}
           total: {}
+        version:
+          dpVersion: {}
+          envoy: {}
 `))
 	})
 
@@ -167,6 +180,18 @@ var _ = Describe("DataplaneStatusTracker", func() {
 		func(given testCase) {
 			// given
 			streamID := int64(1)
+			version := util_proto.MustToStruct(&mesh_proto.Version{
+				DpVersion: &mesh_proto.KumaDpVersion{
+					Version:   "0.0.1",
+					GitTag:    "v0.0.1",
+					GitCommit: "91ce236824a9d875601679aa80c63783fb0e8725",
+					BuildDate: "2019-08-07T11:26:06Z",
+				},
+				Envoy: &mesh_proto.EnvoyVersion{
+					Version: "1.15.0",
+					Build:   "hash/1.15.0/RELEASE",
+				},
+			})
 
 			By("simulating start of subscription")
 			// when
@@ -184,6 +209,20 @@ var _ = Describe("DataplaneStatusTracker", func() {
 			discoveryRequest := &envoy.DiscoveryRequest{
 				Node: &envoy_core.Node{
 					Id: "default.example-001",
+					Metadata: &pstruct.Struct{
+						Fields: map[string]*pstruct.Value{
+							"dataplaneTokenPath": {
+								Kind: &pstruct.Value_StringValue{
+									StringValue: "/tmp/token",
+								},
+							},
+							"version": {
+								Kind: &pstruct.Value_StructValue{
+									StructValue: version,
+								},
+							},
+						},
+					},
 				},
 				TypeUrl: given.TypeUrl,
 			}
@@ -209,6 +248,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
           lds: {}
           rds: {}
           total: {}
+        version:
+          dpVersion:
+            buildDate: "2019-08-07T11:26:06Z"
+            gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+            gitTag: v0.0.1
+            version: 0.0.1
+          envoy:
+            build: hash/1.15.0/RELEASE
+            version: 1.15.0
 `))
 
 			By("simulating initial xDS response")
@@ -285,6 +333,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               rds: {}
               total:
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -301,6 +358,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               total:
                 responsesAcknowledged: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterNACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -319,6 +385,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
                 responsesAcknowledged: "1"
                 responsesRejected: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 		}),
 		Entry("should properly handle RDS flow", testCase{
@@ -336,6 +411,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
                 responsesSent: "1"
               total:
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -352,6 +436,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               total:
                 responsesAcknowledged: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterNACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -370,6 +463,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
                 responsesAcknowledged: "1"
                 responsesRejected: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 		}),
 		Entry("should properly handle CDS flow", testCase{
@@ -387,6 +489,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               rds: {}
               total:
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -403,6 +514,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               total:
                 responsesAcknowledged: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterNACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -421,6 +541,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
                 responsesAcknowledged: "1"
                 responsesRejected: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 		}),
 		Entry("should properly handle EDS flow", testCase{
@@ -438,6 +567,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               rds: {}
               total:
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -454,6 +592,15 @@ var _ = Describe("DataplaneStatusTracker", func() {
               total:
                 responsesAcknowledged: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 			ExpectedStatsAfterNACK: `
             connectTime: "2019-07-01T00:00:00Z"
@@ -472,9 +619,62 @@ var _ = Describe("DataplaneStatusTracker", func() {
                 responsesAcknowledged: "1"
                 responsesRejected: "1"
                 responsesSent: "1"
+            version:
+              dpVersion:
+                buildDate: "2019-08-07T11:26:06Z"
+                gitCommit: 91ce236824a9d875601679aa80c63783fb0e8725
+                gitTag: v0.0.1
+                version: 0.0.1
+              envoy:
+                build: hash/1.15.0/RELEASE
+                version: 1.15.0
 `,
 		}),
 	)
+
+	type versionTestCase struct {
+		version *pstruct.Value
+	}
+
+	DescribeTable("should read node.metadata without error",
+		func(given versionTestCase) {
+			// given
+			version := mesh_proto.NewVersion()
+			node := &envoy_core.Node{
+				Metadata: &pstruct.Struct{
+					Fields: map[string]*pstruct.Value{
+						"dataplaneTokenPath": {
+							Kind: &pstruct.Value_StringValue{
+								StringValue: "/tmp/token",
+							},
+						},
+						"version": given.version,
+					},
+				},
+			}
+
+			// when
+			err := readVersion(node.Metadata, version)
+
+			// then
+			Expect(err).To(BeNil())
+			Expect(version).To(Equal(mesh_proto.NewVersion()))
+		},
+		Entry("when version is a nil struct", versionTestCase{
+			version: &pstruct.Value{
+				Kind: &pstruct.Value_StructValue{
+					StructValue: nil,
+				},
+			},
+		}),
+		Entry("when version is not a struct", versionTestCase{
+			version: &pstruct.Value{
+				Kind: &pstruct.Value_StringValue{
+					StringValue: "v1.0.0",
+				},
+			},
+		}),
+	)
 })
 
 type DataplaneInsightSinkFunc func(stop <-chan struct{})