mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-02 07:34:45 +08:00
feat(extensions)!: normalize protocol negotiation (#3352)
* feat(extensions)!: normalize protocol negotiation Closes #3057 Introduce a shared extension handshake, enforce protocol and capability compatibility across extension families, and expose immutable negotiated snapshots through gateway info and the Go SDK. Signed-off-by: Seth Jennings <sjenning@redhat.com> * fix(credentials): fail fast on negotiation errors Signed-off-by: Seth Jennings <sjenning@redhat.com> * fix(extensions): validate gateway handshake metadata Signed-off-by: Seth Jennings <sjenning@redhat.com> * fix(go-sdk): re-export extension kind constants Signed-off-by: Seth Jennings <sjenning@redhat.com> * fix(extensions): fail fast on credential handshake rejection Signed-off-by: Seth Jennings <sjenning@redhat.com> --------- Signed-off-by: Seth Jennings <sjenning@redhat.com>
This commit is contained in:
@@ -89,6 +89,14 @@ func copyGatewayInfo(info *types.GatewayInfo) *types.GatewayInfo {
|
||||
cp.ComputeDrivers = make([]types.ComputeDriverInfo, len(info.ComputeDrivers))
|
||||
copy(cp.ComputeDrivers, info.ComputeDrivers)
|
||||
}
|
||||
if info.Extensions != nil {
|
||||
cp.Extensions = make([]types.ExtensionInfo, len(info.Extensions))
|
||||
for index, extension := range info.Extensions {
|
||||
cp.Extensions[index] = extension
|
||||
cp.Extensions[index].SupportedCapabilities = copyStringSlice(extension.SupportedCapabilities)
|
||||
cp.Extensions[index].RequiredCapabilities = copyStringSlice(extension.RequiredCapabilities)
|
||||
}
|
||||
}
|
||||
return &cp
|
||||
}
|
||||
|
||||
|
||||
@@ -84,13 +84,21 @@ func TestHealth_GetGatewayInfo_DeepCopy(t *testing.T) {
|
||||
ComputeDrivers: []types.ComputeDriverInfo{
|
||||
{Name: "k8s"},
|
||||
},
|
||||
Extensions: []types.ExtensionInfo{{
|
||||
ConfiguredName: "k8s",
|
||||
SupportedCapabilities: []string{"openshell.compute.contract"},
|
||||
}},
|
||||
}))
|
||||
|
||||
info1, _ := fc.Health().GetGatewayInfo(context.Background())
|
||||
info1.ComputeDrivers[0].Name = "mutated"
|
||||
info1.Extensions[0].ConfiguredName = "mutated"
|
||||
info1.Extensions[0].SupportedCapabilities[0] = "mutated"
|
||||
|
||||
info2, _ := fc.Health().GetGatewayInfo(context.Background())
|
||||
assert.Equal(t, "k8s", info2.ComputeDrivers[0].Name)
|
||||
assert.Equal(t, "k8s", info2.Extensions[0].ConfiguredName)
|
||||
assert.Equal(t, "openshell.compute.contract", info2.Extensions[0].SupportedCapabilities[0])
|
||||
}
|
||||
|
||||
func TestHealth_GetCurrentUser_Default(t *testing.T) {
|
||||
|
||||
@@ -18,6 +18,21 @@ type GatewayInfo = types.GatewayInfo
|
||||
// ComputeDriverInfo describes a compute backend available on the gateway.
|
||||
type ComputeDriverInfo = types.ComputeDriverInfo
|
||||
|
||||
// ExtensionInfo describes one successful gateway/extension negotiation.
|
||||
type ExtensionInfo = types.ExtensionInfo
|
||||
|
||||
// ExtensionKind identifies one supported extension family.
|
||||
type ExtensionKind = types.ExtensionKind
|
||||
|
||||
// ExtensionKind constants re-exported from the types package.
|
||||
const (
|
||||
ExtensionKindComputeDriver = types.ExtensionKindComputeDriver
|
||||
ExtensionKindCredentialDriver = types.ExtensionKindCredentialDriver
|
||||
ExtensionKindGatewayInterceptor = types.ExtensionKindGatewayInterceptor
|
||||
ExtensionKindSupervisorMiddleware = types.ExtensionKindSupervisorMiddleware
|
||||
ExtensionKindUnknown = types.ExtensionKindUnknown
|
||||
)
|
||||
|
||||
// ServiceStatus describes the health state of the gateway.
|
||||
type ServiceStatus = types.ServiceStatus
|
||||
|
||||
|
||||
@@ -31,6 +31,14 @@ type mockHealthServer struct {
|
||||
currentUserErr error
|
||||
}
|
||||
|
||||
func TestExtensionKindConstantsAreReexported(t *testing.T) {
|
||||
assert.Equal(t, ExtensionKind("ComputeDriver"), ExtensionKindComputeDriver)
|
||||
assert.Equal(t, ExtensionKind("CredentialDriver"), ExtensionKindCredentialDriver)
|
||||
assert.Equal(t, ExtensionKind("GatewayInterceptor"), ExtensionKindGatewayInterceptor)
|
||||
assert.Equal(t, ExtensionKind("SupervisorMiddleware"), ExtensionKindSupervisorMiddleware)
|
||||
assert.Equal(t, ExtensionKind("Unknown"), ExtensionKindUnknown)
|
||||
}
|
||||
|
||||
func (s *mockHealthServer) Health(_ context.Context, _ *pb.HealthRequest) (*pb.HealthResponse, error) {
|
||||
if s.err != nil {
|
||||
return nil, s.err
|
||||
|
||||
@@ -18,11 +18,46 @@ func GatewayInfoFromProto(resp *pb.GetGatewayInfoResponse) *types.GatewayInfo {
|
||||
for _, d := range resp.GetComputeDrivers() {
|
||||
drivers = append(drivers, ComputeDriverInfoFromProto(d))
|
||||
}
|
||||
extensions := make([]types.ExtensionInfo, 0, len(resp.GetExtensions()))
|
||||
for _, extension := range resp.GetExtensions() {
|
||||
extensions = append(extensions, ExtensionInfoFromProto(extension))
|
||||
}
|
||||
|
||||
return &types.GatewayInfo{
|
||||
Status: ServiceStatusFromProto(resp.GetStatus()),
|
||||
Version: resp.GetGatewayVersion(),
|
||||
ComputeDrivers: drivers,
|
||||
Extensions: extensions,
|
||||
}
|
||||
}
|
||||
|
||||
// ExtensionInfoFromProto converts a negotiated extension snapshot.
|
||||
func ExtensionInfoFromProto(extension *pb.NegotiatedExtensionInfo) types.ExtensionInfo {
|
||||
return types.ExtensionInfo{
|
||||
Kind: ExtensionKindFromProto(extension.GetKind()),
|
||||
ConfiguredName: extension.GetConfiguredName(),
|
||||
ImplementationName: extension.GetImplementationName(),
|
||||
ImplementationVersion: extension.GetImplementationVersion(),
|
||||
ProtocolMajor: extension.GetProtocolMajor(),
|
||||
ProtocolMinor: extension.GetProtocolMinor(),
|
||||
SupportedCapabilities: CopyStringSlice(extension.GetSupportedCapabilities()),
|
||||
RequiredCapabilities: CopyStringSlice(extension.GetRequiredCapabilities()),
|
||||
}
|
||||
}
|
||||
|
||||
// ExtensionKindFromProto converts the public extension family enum.
|
||||
func ExtensionKindFromProto(kind pb.ExtensionKind) types.ExtensionKind {
|
||||
switch kind {
|
||||
case pb.ExtensionKind_EXTENSION_KIND_COMPUTE_DRIVER:
|
||||
return types.ExtensionKindComputeDriver
|
||||
case pb.ExtensionKind_EXTENSION_KIND_CREDENTIAL_DRIVER:
|
||||
return types.ExtensionKindCredentialDriver
|
||||
case pb.ExtensionKind_EXTENSION_KIND_GATEWAY_INTERCEPTOR:
|
||||
return types.ExtensionKindGatewayInterceptor
|
||||
case pb.ExtensionKind_EXTENSION_KIND_SUPERVISOR_MIDDLEWARE:
|
||||
return types.ExtensionKindSupervisorMiddleware
|
||||
default:
|
||||
return types.ExtensionKindUnknown
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,17 @@ func TestGatewayInfoFromProto(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Extensions: []*pb.NegotiatedExtensionInfo{
|
||||
{
|
||||
Kind: pb.ExtensionKind_EXTENSION_KIND_COMPUTE_DRIVER,
|
||||
ConfiguredName: "k8s",
|
||||
ImplementationName: "openshell/kubernetes",
|
||||
ImplementationVersion: "1.5.0",
|
||||
ProtocolMajor: 1,
|
||||
SupportedCapabilities: []string{"openshell.compute.contract"},
|
||||
RequiredCapabilities: []string{"openshell.compute.contract"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
info := GatewayInfoFromProto(proto)
|
||||
@@ -45,6 +56,10 @@ func TestGatewayInfoFromProto(t *testing.T) {
|
||||
assert.Equal(t, "2.1.0", info.ComputeDrivers[0].DriverVersion)
|
||||
assert.Equal(t, "docker", info.ComputeDrivers[1].Name)
|
||||
assert.Equal(t, "docker-engine", info.ComputeDrivers[1].DriverName)
|
||||
require.Len(t, info.Extensions, 1)
|
||||
assert.Equal(t, v1.ExtensionKindComputeDriver, info.Extensions[0].Kind)
|
||||
assert.Equal(t, "openshell/kubernetes", info.Extensions[0].ImplementationName)
|
||||
assert.Equal(t, uint32(1), info.Extensions[0].ProtocolMajor)
|
||||
}
|
||||
|
||||
func TestGatewayInfoFromProto_NoDrivers(t *testing.T) {
|
||||
@@ -72,12 +87,20 @@ func TestGatewayInfoFromProto_DeepCopy(t *testing.T) {
|
||||
ComputeDrivers: []*pb.ComputeDriverInfo{
|
||||
{Name: "k8s", Capabilities: &pb.ComputeDriverCapabilities{DriverName: "kubernetes"}},
|
||||
},
|
||||
Extensions: []*pb.NegotiatedExtensionInfo{{
|
||||
ConfiguredName: "k8s",
|
||||
SupportedCapabilities: []string{"openshell.compute.contract"},
|
||||
}},
|
||||
}
|
||||
|
||||
info := GatewayInfoFromProto(proto)
|
||||
proto.ComputeDrivers[0].Name = "mutated"
|
||||
proto.Extensions[0].ConfiguredName = "mutated"
|
||||
proto.Extensions[0].SupportedCapabilities[0] = "mutated"
|
||||
|
||||
assert.Equal(t, "k8s", info.ComputeDrivers[0].Name)
|
||||
assert.Equal(t, "k8s", info.Extensions[0].ConfiguredName)
|
||||
assert.Equal(t, "openshell.compute.contract", info.Extensions[0].SupportedCapabilities[0])
|
||||
}
|
||||
|
||||
func TestServiceStatusFromProto(t *testing.T) {
|
||||
|
||||
@@ -25,6 +25,31 @@ type GatewayInfo struct {
|
||||
Status ServiceStatus
|
||||
Version string
|
||||
ComputeDrivers []ComputeDriverInfo
|
||||
Extensions []ExtensionInfo
|
||||
}
|
||||
|
||||
// ExtensionKind identifies one supported extension family.
|
||||
type ExtensionKind string
|
||||
|
||||
// Extension kind constants.
|
||||
const (
|
||||
ExtensionKindComputeDriver ExtensionKind = "ComputeDriver"
|
||||
ExtensionKindCredentialDriver ExtensionKind = "CredentialDriver"
|
||||
ExtensionKindGatewayInterceptor ExtensionKind = "GatewayInterceptor"
|
||||
ExtensionKindSupervisorMiddleware ExtensionKind = "SupervisorMiddleware"
|
||||
ExtensionKindUnknown ExtensionKind = "Unknown"
|
||||
)
|
||||
|
||||
// ExtensionInfo describes one successful gateway/extension negotiation.
|
||||
type ExtensionInfo struct {
|
||||
Kind ExtensionKind
|
||||
ConfiguredName string
|
||||
ImplementationName string
|
||||
ImplementationVersion string
|
||||
ProtocolMajor uint32
|
||||
ProtocolMinor uint32
|
||||
SupportedCapabilities []string
|
||||
RequiredCapabilities []string
|
||||
}
|
||||
|
||||
// ComputeDriverInfo describes a compute backend available on the gateway.
|
||||
|
||||
+1679
-1487
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user