2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2018-08-13 17:29:29 +00:00
|
|
|
package device
|
|
|
|
|
|
|
|
import (
|
2022-07-28 18:46:56 +00:00
|
|
|
"context"
|
2018-09-28 17:09:01 +00:00
|
|
|
"fmt"
|
|
|
|
"time"
|
2018-08-13 17:29:29 +00:00
|
|
|
|
2018-09-28 17:09:01 +00:00
|
|
|
"github.com/golang/protobuf/ptypes"
|
2022-07-28 18:46:56 +00:00
|
|
|
"github.com/hashicorp/go-plugin"
|
|
|
|
|
2018-08-13 17:29:29 +00:00
|
|
|
"github.com/hashicorp/nomad/plugins/device/proto"
|
|
|
|
)
|
|
|
|
|
|
|
|
// devicePluginServer wraps a device plugin and exposes it via gRPC.
|
|
|
|
type devicePluginServer struct {
|
|
|
|
broker *plugin.GRPCBroker
|
|
|
|
impl DevicePlugin
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *devicePluginServer) Fingerprint(req *proto.FingerprintRequest, stream proto.DevicePlugin_FingerprintServer) error {
|
|
|
|
ctx := stream.Context()
|
|
|
|
outCh, err := d.impl.Fingerprint(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return nil
|
|
|
|
case resp, ok := <-outCh:
|
|
|
|
// The output channel has been closed, end the stream
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle any error
|
|
|
|
if resp.Error != nil {
|
|
|
|
return resp.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the devices
|
|
|
|
out := convertStructDeviceGroups(resp.Devices)
|
|
|
|
|
|
|
|
// Build the response
|
|
|
|
presp := &proto.FingerprintResponse{
|
|
|
|
DeviceGroup: out,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the devices
|
|
|
|
if err := stream.Send(presp); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *devicePluginServer) Reserve(ctx context.Context, req *proto.ReserveRequest) (*proto.ReserveResponse, error) {
|
|
|
|
resp, err := d.impl.Reserve(req.GetDeviceIds())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the response
|
|
|
|
presp := &proto.ReserveResponse{
|
|
|
|
ContainerRes: convertStructContainerReservation(resp),
|
|
|
|
}
|
|
|
|
|
|
|
|
return presp, nil
|
|
|
|
}
|
2018-08-27 23:11:07 +00:00
|
|
|
|
|
|
|
func (d *devicePluginServer) Stats(req *proto.StatsRequest, stream proto.DevicePlugin_StatsServer) error {
|
|
|
|
ctx := stream.Context()
|
2018-09-28 17:09:01 +00:00
|
|
|
|
|
|
|
// Retrieve the collection interval
|
|
|
|
interval, err := ptypes.Duration(req.CollectionInterval)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to parse collection interval: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default the duration if we get an invalid duration
|
|
|
|
if interval.Nanoseconds() == 0 {
|
|
|
|
interval = time.Second
|
|
|
|
}
|
|
|
|
|
|
|
|
outCh, err := d.impl.Stats(ctx, interval)
|
2018-08-27 23:11:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return nil
|
|
|
|
case resp, ok := <-outCh:
|
|
|
|
// The output channel has been closed, end the stream
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle any error
|
|
|
|
if resp.Error != nil {
|
|
|
|
return resp.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the devices
|
|
|
|
out := convertStructDeviceGroupsStats(resp.Groups)
|
|
|
|
|
|
|
|
// Build the response
|
|
|
|
presp := &proto.StatsResponse{
|
|
|
|
Groups: out,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the devices
|
|
|
|
if err := stream.Send(presp); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|