Merge pull request #358 from rojkov/webhook-modeless

fpga: make admission webhook mode-less
This commit is contained in:
Ed Bartosh 2020-05-05 10:24:13 +03:00 committed by GitHub
commit 8b429fd99d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 949 additions and 955 deletions

View File

@ -162,7 +162,7 @@ https://github.com/kubernetes/code-generator/blob/master/generate-groups.sh
```
$ generate-groups.sh all github.com/intel/intel-device-plugins-for-kubernetes/pkg/client \
github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis \
fpga.intel.com:v1
fpga.intel.com:v2
```
Please note that the script (at least of v0.18.2-beta.0) expects the device plugins

View File

@ -30,16 +30,6 @@ The admission controller also keeps the user from bypassing namespaced mapping r
by denying admission of any pods that are trying to use internal knowledge of InterfaceID or
Bitstream ID environment variables used by the prestart hook.
The admission controller can operate in two separate modes - preprogrammed or orchestration programmed.
The mode must be chosen to match that of the [FPGA plugin](../fpga_plugin/README.md) configuraton, as
shown in the following table:
| FPGA plugin mode | matching admission controller mode |
|:---------------- |:---------------------------------- |
| region | orchestrated |
| af | preprogrammed |
# Dependencies
This component is one of a set of components that work together. You may also want to
@ -118,14 +108,6 @@ Register webhook
mutatingwebhookconfiguration.admissionregistration.k8s.io/fpga-mutator-webhook-cfg created
```
By default, the script deploys the webhook in a preprogrammed mode.
Use the option `--mode` script option to deploy the webhook in orchestrated mode:
```bash
$ ./scripts/webhook-deploy.sh --mode orchestrated
```
The script needs the CA bundle used for signing certificate requests in your cluster.
By default, the script fetches the bundle stored in the configmap
`extension-apiserver-authentication`. However, your cluster may use a different signing
@ -138,13 +120,41 @@ $ ./scripts/webhook-deploy.sh --ca-bundle-path /var/run/kubernetes/server-ca.crt
# Mappings
Requested FPGA resources are translated to AF resources. For example,
`fpga.intel.com/arria10.dcp1.1-nlb0` is translated to `fpga.intel.com/af-d8424dc4a4a3c413f89e433683f9040b`.
Mappings is a an essential part of the setup that gives a flexible instrument to a cluster
administrator to manage FPGA bitstreams and to control access to them. Being a set of
custom resource definitions they are used to configure the way FPGA resource requests get
translated into actual resources provided by the cluster.
In orchestrated mode, `fpga.intel.com/arria10.dcp1.1-nlb0` gets translated to
`fpga.intel.com/region-9926ab6d6c925a68aabca7d84c545738`, and, the corresponding AF IDs are set in
environment variables for the container. The [FPGA CRI-O hook](../fpga_crihook/README.md)
then loads the requested bitstream to a region before the container is started.
For the following mapping
```yaml
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.2-nlb0-preprogrammed
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
interfaceId: 69528db6eb31577a8c3668f9faa081f6
mode: af
```
requested FPGA resources are translated to AF resources. For example,
`fpga.intel.com/arria10.dcp1.2-nlb0-preprogrammed` is translated to
`fpga.intel.com/af-695.d84.aVKNtusxV3qMNmj5-qCB9thCTcSko8QT-J5DNoP5BAs` where the `af-`
prefix indicates the plugin's mode (`af`), `695` is the first three characters of
the region interface ID, `d84` is the first three characters of the accelerator function ID
and the last part `aVKNtusxV3qMNmj5-qCB9thCTcSko8QT-J5DNoP5BAs` is a base64-encoded concatenation
of the full region interface ID and accelerator function ID.
The format of resource names (e.g. `arria10.dcp1.2-nlb0-preprogrammed`) can be any and is up
to a cluster administrator.
The same mapping, but with its mode field set to `region`, would translate
`fpga.intel.com/arria10.dcp1.2-nlb0-preprogrammed` to `fpga.intel.com/region-69528db6eb31577a8c3668f9faa081f6`,
and the corresponding AF IDs are set in environment variables for the container.
Though in this case the cluster administrator would probably want to rename
the mapping `arria10.dcp1.2-nlb0-preprogrammed` to something like `arria10.dcp1.2-nlb0-orchestrated`
to reflect its mode. The [FPGA CRI-O hook](../fpga_crihook/README.md) then loads the requested
bitstream to a region before the container is started.
Mappings of resource names are configured with objects of `AcceleratorFunction` and
`FpgaRegion` custom resource definitions found respectively in

View File

@ -29,7 +29,7 @@ import (
clientset "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned"
informers "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions"
listers "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v1"
listers "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v2"
)
const (
@ -42,7 +42,7 @@ type fpgaObjectKey struct {
}
type controller struct {
patcherManager *patcherManager
patcherManager patcherManager
informerFactory informers.SharedInformerFactory
afsSynced cache.InformerSynced
regionsSynced cache.InformerSynced
@ -52,7 +52,7 @@ type controller struct {
stopCh chan struct{}
}
func newController(patcherManager *patcherManager, config *rest.Config) (*controller, error) {
func newController(patcherManager patcherManager, config *rest.Config) (*controller, error) {
clientset, err := clientset.NewForConfig(config)
if err != nil {
return nil, errors.Wrap(err, "Failed to create REST clientset")
@ -61,8 +61,8 @@ func newController(patcherManager *patcherManager, config *rest.Config) (*contro
informerFactory := informers.NewSharedInformerFactory(clientset, resyncPeriod)
stopCh := make(chan struct{})
afInformer := informerFactory.Fpga().V1().AcceleratorFunctions()
regionInformer := informerFactory.Fpga().V1().FpgaRegions()
afInformer := informerFactory.Fpga().V2().AcceleratorFunctions()
regionInformer := informerFactory.Fpga().V2().FpgaRegions()
controller := &controller{
patcherManager: patcherManager,
@ -172,11 +172,7 @@ func (c *controller) syncAfHandler(key string) error {
return nil
}
patcher, err := c.patcherManager.getPatcher(namespace)
if err != nil {
runtime.HandleError(errors.Wrapf(err, "can't get patcher for namespace %s", namespace))
return nil
}
patcher := c.patcherManager.getPatcher(namespace)
// Get the AcceleratorFunction resource with this namespace/name
af, err := c.afLister.AcceleratorFunctions(namespace).Get(name)
@ -194,8 +190,7 @@ func (c *controller) syncAfHandler(key string) error {
}
klog.V(4).Info("Received", af)
patcher.addAf(af)
return nil
return patcher.addAf(af)
}
func (c *controller) syncRegionHandler(key string) error {
@ -206,11 +201,7 @@ func (c *controller) syncRegionHandler(key string) error {
return nil
}
patcher, err := c.patcherManager.getPatcher(namespace)
if err != nil {
runtime.HandleError(errors.Wrapf(err, "can't get patcher for namespace %s", namespace))
return nil
}
patcher := c.patcherManager.getPatcher(namespace)
// Get the FpgaRegion resource with this namespace/name
region, err := c.regionLister.FpgaRegions(namespace).Get(name)

View File

@ -24,12 +24,12 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/rest"
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
listers "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
listers "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v2"
)
type fakeAfNamespaceLister struct {
af *v1.AcceleratorFunction
af *v2.AcceleratorFunction
err error
}
@ -37,16 +37,16 @@ func init() {
flag.Set("v", "4") ///Enable debug output
}
func (nl *fakeAfNamespaceLister) Get(name string) (*v1.AcceleratorFunction, error) {
func (nl *fakeAfNamespaceLister) Get(name string) (*v2.AcceleratorFunction, error) {
return nl.af, nl.err
}
func (nl *fakeAfNamespaceLister) List(selector labels.Selector) (ret []*v1.AcceleratorFunction, err error) {
func (nl *fakeAfNamespaceLister) List(selector labels.Selector) (ret []*v2.AcceleratorFunction, err error) {
return nil, nil
}
type fakeAfLister struct {
af *v1.AcceleratorFunction
af *v2.AcceleratorFunction
err error
}
@ -57,17 +57,16 @@ func (l *fakeAfLister) AcceleratorFunctions(namespace string) listers.Accelerato
}
}
func (l *fakeAfLister) List(selector labels.Selector) (ret []*v1.AcceleratorFunction, err error) {
func (l *fakeAfLister) List(selector labels.Selector) (ret []*v2.AcceleratorFunction, err error) {
return nil, nil
}
func TestSyncAfHandler(t *testing.T) {
tcases := []struct {
name string
key string
afLister *fakeAfLister
patcherManagerIsBroken bool
expectedErr bool
name string
key string
afLister *fakeAfLister
expectedErr bool
}{
{
name: "Wrong key format",
@ -77,21 +76,16 @@ func TestSyncAfHandler(t *testing.T) {
name: "Known key",
key: "default/arria10-nlb0",
afLister: &fakeAfLister{
af: &v1.AcceleratorFunction{
af: &v2.AcceleratorFunction{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0",
},
Spec: v1.AcceleratorFunctionSpec{
Spec: v2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
},
},
},
},
{
name: "Broken patcher manager",
key: "default/arria10-nlb0",
patcherManagerIsBroken: true,
},
{
name: "Unknown key",
key: "default/unknown",
@ -107,13 +101,7 @@ func TestSyncAfHandler(t *testing.T) {
}
for _, tt := range tcases {
pm, err := newPatcherManager(preprogrammed)
if err != nil {
t.Fatalf("Test case '%s': %+v", tt.name, err)
}
if tt.patcherManagerIsBroken {
pm.defaultMode = "broken"
}
pm := newPatcherManager()
c, err := newController(pm, &rest.Config{})
if err != nil {
t.Fatalf("Test case '%s': %+v", tt.name, err)
@ -132,20 +120,20 @@ func TestSyncAfHandler(t *testing.T) {
}
type fakeRegionNamespaceLister struct {
region *v1.FpgaRegion
region *v2.FpgaRegion
err error
}
func (nl *fakeRegionNamespaceLister) Get(name string) (*v1.FpgaRegion, error) {
func (nl *fakeRegionNamespaceLister) Get(name string) (*v2.FpgaRegion, error) {
return nl.region, nl.err
}
func (nl *fakeRegionNamespaceLister) List(selector labels.Selector) (ret []*v1.FpgaRegion, err error) {
func (nl *fakeRegionNamespaceLister) List(selector labels.Selector) (ret []*v2.FpgaRegion, err error) {
return nil, nil
}
type fakeRegionLister struct {
region *v1.FpgaRegion
region *v2.FpgaRegion
err error
}
@ -156,17 +144,16 @@ func (l *fakeRegionLister) FpgaRegions(namespace string) listers.FpgaRegionNames
}
}
func (l *fakeRegionLister) List(selector labels.Selector) (ret []*v1.FpgaRegion, err error) {
func (l *fakeRegionLister) List(selector labels.Selector) (ret []*v2.FpgaRegion, err error) {
return nil, nil
}
func TestSyncRegionHandler(t *testing.T) {
tcases := []struct {
name string
key string
patcherManagerIsBroken bool
regionLister *fakeRegionLister
expectedErr bool
name string
key string
regionLister *fakeRegionLister
expectedErr bool
}{
{
name: "Wrong key format",
@ -176,21 +163,16 @@ func TestSyncRegionHandler(t *testing.T) {
name: "Known key",
key: "default/arria10",
regionLister: &fakeRegionLister{
region: &v1.FpgaRegion{
region: &v2.FpgaRegion{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10",
},
Spec: v1.FpgaRegionSpec{
Spec: v2.FpgaRegionSpec{
InterfaceID: "ce48969398f05f33946d560708be108a",
},
},
},
},
{
name: "Broken patcher manager",
key: "default/arria10",
patcherManagerIsBroken: true,
},
{
name: "Unknown key",
key: "default/unknown",
@ -206,13 +188,7 @@ func TestSyncRegionHandler(t *testing.T) {
}
for _, tt := range tcases {
pm, err := newPatcherManager(preprogrammed)
if err != nil {
t.Fatalf("Test case '%s': %+v", tt.name, err)
}
if tt.patcherManagerIsBroken {
pm.defaultMode = "broken"
}
pm := newPatcherManager()
c, err := newController(pm, &rest.Config{})
if err != nil {
t.Fatalf("Test case '%s': %+v", tt.name, err)
@ -328,7 +304,7 @@ func TestProcessNextWorkItem(t *testing.T) {
},
}
for _, tt := range tcases {
pm, _ := newPatcherManager(preprogrammed)
pm := newPatcherManager()
c, err := newController(pm, &rest.Config{})
if err != nil {
t.Fatalf("Test case '%s': %+v", tt.name, err)
@ -352,9 +328,9 @@ func TestProcessNextWorkItem(t *testing.T) {
func TestCreateEventhandler(t *testing.T) {
funcs := createEventHandler("testkind", &fakeQueue{})
funcs.AddFunc(&v1.FpgaRegion{})
funcs.UpdateFunc(nil, &v1.FpgaRegion{})
funcs.DeleteFunc(&v1.FpgaRegion{})
funcs.AddFunc(&v2.FpgaRegion{})
funcs.UpdateFunc(nil, &v2.FpgaRegion{})
funcs.DeleteFunc(&v2.FpgaRegion{})
}
func TestRun(t *testing.T) {
@ -369,7 +345,7 @@ func TestRun(t *testing.T) {
}
for _, tt := range tcases {
pm := &patcherManager{}
pm := newPatcherManager()
c, err := newController(pm, &rest.Config{})
if err != nil {
t.Fatalf("Test case '%s': %+v", tt.name, err)
@ -404,7 +380,7 @@ func TestNewController(t *testing.T) {
config := &rest.Config{
Host: tt.configHost,
}
pm := &patcherManager{}
pm := newPatcherManager()
c, err := newController(pm, config)
if err != nil && !tt.expectedErr {
t.Errorf("Test case '%s': unexpected error: %+v", tt.name, err)

View File

@ -18,7 +18,6 @@ import (
"crypto/tls"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
@ -39,8 +38,6 @@ import (
)
const (
preprogrammed = "preprogrammed"
orchestrated = "orchestrated"
controllerThreadNum = 1
)
@ -69,7 +66,7 @@ func getTLSConfig(certFile string, keyFile string) *tls.Config {
}
}
func mutatePods(ar v1beta1.AdmissionReview, pm *patcherManager) *v1beta1.AdmissionResponse {
func mutatePods(ar v1beta1.AdmissionReview, pm patcherManager) *v1beta1.AdmissionResponse {
var ops []string
klog.V(4).Info("mutating pods")
@ -97,11 +94,7 @@ func mutatePods(ar v1beta1.AdmissionReview, pm *patcherManager) *v1beta1.Admissi
name = pod.ObjectMeta.GenerateName
}
klog.V(4).Infof("Received pod '%s' in name space '%s'", name, namespace)
patcher, err := pm.getPatcher(namespace)
if err != nil {
klog.Warningf("%+v", err)
return toAdmissionResponse(err)
}
patcher := pm.getPatcher(namespace)
reviewResponse := v1beta1.AdmissionResponse{}
reviewResponse.Allowed = true
@ -198,7 +191,7 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
}
}
func makePodsHandler(pm *patcherManager) func(w http.ResponseWriter, r *http.Request) {
func makePodsHandler(pm patcherManager) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
serve(w, r, func(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
return mutatePods(ar, pm)
@ -211,7 +204,6 @@ func main() {
var master string
var certFile string
var keyFile string
var mode string
var config *rest.Config
var err error
@ -220,7 +212,6 @@ func main() {
flag.StringVar(&certFile, "tls-cert-file", certFile,
"File containing the x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert).")
flag.StringVar(&keyFile, "tls-private-key-file", keyFile, "File containing the x509 private key matching --tls-cert-file.")
flag.StringVar(&mode, "mode", preprogrammed, fmt.Sprintf("webhook mode: '%s' (default) or '%s'", preprogrammed, orchestrated))
flag.Parse()
if certFile == "" {
@ -248,18 +239,15 @@ func main() {
klog.Fatal("Failed to get cluster config ", err)
}
patcherManager, err := newPatcherManager(mode)
if err != nil {
klog.Fatalf("%+v", err)
}
pm := newPatcherManager()
controller, err := newController(patcherManager, config)
controller, err := newController(pm, config)
if err != nil {
klog.Fatalf("%+v", err)
}
go controller.run(controllerThreadNum)
http.HandleFunc("/pods", makePodsHandler(patcherManager))
http.HandleFunc("/pods", makePodsHandler(pm))
klog.V(4).Info("Webhook started")

View File

@ -24,6 +24,7 @@ import (
"strings"
"testing"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
"k8s.io/api/admission/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
@ -144,16 +145,39 @@ func TestMutatePods(t *testing.T) {
},
},
}
brokenPod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "test-container",
Image: "test-image",
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"cpu": resource.MustParse("1"),
"fpga.intel.com/arria10": resource.MustParse("1"),
},
},
},
},
},
}
podRaw, err := json.Marshal(pod)
if err != nil {
t.Fatal(err)
}
brokenPodRaw, err := json.Marshal(brokenPod)
if err != nil {
t.Fatal(err)
}
tcases := []struct {
name string
mode string
ar v1beta1.AdmissionReview
expectedResponse bool
expectedAllowed bool
expectedPatchOps int
}{
{
@ -161,7 +185,6 @@ func TestMutatePods(t *testing.T) {
ar: v1beta1.AdmissionReview{
Request: &v1beta1.AdmissionRequest{},
},
mode: preprogrammed,
},
{
name: "admission request without object",
@ -170,8 +193,8 @@ func TestMutatePods(t *testing.T) {
Resource: metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
},
},
mode: preprogrammed,
expectedResponse: true,
expectedAllowed: true,
},
{
name: "admission request with corrupted object",
@ -183,11 +206,10 @@ func TestMutatePods(t *testing.T) {
},
},
},
mode: preprogrammed,
expectedResponse: true,
},
{
name: "non-empty admission request in preprogrammed mode",
name: "successful non-empty admission request",
ar: v1beta1.AdmissionReview{
Request: &v1beta1.AdmissionRequest{
Resource: metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
@ -196,23 +218,9 @@ func TestMutatePods(t *testing.T) {
},
},
},
mode: preprogrammed,
expectedResponse: true,
expectedPatchOps: 4,
},
{
name: "non-empty admission request in orchestrated mode",
ar: v1beta1.AdmissionReview{
Request: &v1beta1.AdmissionRequest{
Resource: metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
Object: runtime.RawExtension{
Raw: podRaw,
},
},
},
mode: orchestrated,
expectedResponse: true,
expectedPatchOps: 5,
expectedAllowed: true,
},
{
name: "handle error after wrong getPatchOps()",
@ -220,48 +228,54 @@ func TestMutatePods(t *testing.T) {
Request: &v1beta1.AdmissionRequest{
Resource: metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
Object: runtime.RawExtension{
Raw: podRaw,
Raw: brokenPodRaw,
},
},
},
mode: "unknown mode",
expectedResponse: true,
},
}
for _, tcase := range tcases {
p := &patcher{
mode: tcase.mode,
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
resourceMap: map[string]string{
"fpga.intel.com/arria10": "ce48969398f05f33946d560708be108a",
},
}
pm := &patcherManager{
defaultMode: tcase.mode,
patchers: map[string]*patcher{
"default": p,
},
}
resp := mutatePods(tcase.ar, pm)
t.Run(tcase.name, func(t *testing.T) {
p := newPatcher()
p.addRegion(&fpgav2.FpgaRegion{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10",
},
Spec: fpgav2.FpgaRegionSpec{
InterfaceID: "ce48969398f05f33946d560708be108a",
},
})
pm := newPatcherManager()
pm["default"] = p
resp := mutatePods(tcase.ar, pm)
if !tcase.expectedResponse && resp != nil {
t.Errorf("Test case '%s': got unexpected response", tcase.name)
} else if tcase.expectedResponse && resp == nil {
t.Errorf("Test case '%s': got no response", tcase.name)
} else if tcase.expectedResponse && tcase.expectedPatchOps > 0 {
var ops interface{}
actualPatchOps := 0
if !tcase.expectedResponse && resp != nil {
t.Errorf("Test case '%s': got unexpected response", tcase.name)
} else if tcase.expectedResponse && resp == nil {
t.Errorf("Test case '%s': got no response", tcase.name)
} else if tcase.expectedResponse {
if tcase.expectedAllowed != resp.Allowed {
t.Errorf("Allowed expected to be %t but got %t", tcase.expectedAllowed, resp.Allowed)
} else if resp.Allowed && resp.Patch != nil {
var ops interface{}
err := json.Unmarshal(resp.Patch, &ops)
if err != nil {
t.Errorf("Test case '%s': got unparsable patch '%s'", tcase.name, resp.Patch)
} else if len(ops.([]interface{})) != tcase.expectedPatchOps {
t.Errorf("Test case '%s': got wrong number of operations in the patch. Expected %d, but got %d\n%s",
tcase.name, tcase.expectedPatchOps, len(ops.([]interface{})), string(resp.Patch))
err := json.Unmarshal(resp.Patch, &ops)
if err != nil {
t.Errorf("Test case '%s': got unparsable patch '%s'", tcase.name, resp.Patch)
} else {
actualPatchOps = len(ops.([]interface{}))
}
}
}
}
if actualPatchOps != tcase.expectedPatchOps {
t.Errorf("Test case '%s': got wrong number of operations in the patch. Expected %d, but got %d\n%s",
tcase.name, tcase.expectedPatchOps, actualPatchOps, string(resp.Patch))
}
})
}
}
@ -280,6 +294,6 @@ func (*fakeResponseWriter) WriteHeader(int) {
}
func TestMakePodsHandler(t *testing.T) {
serveFunc := makePodsHandler(&patcherManager{})
serveFunc := makePodsHandler(newPatcherManager())
serveFunc(&fakeResponseWriter{}, &http.Request{})
}

View File

@ -17,7 +17,6 @@ package main
import (
"bytes"
"fmt"
"regexp"
"strings"
"sync"
"text/template"
@ -27,20 +26,19 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/klog"
fpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
"github.com/intel/intel-device-plugins-for-kubernetes/pkg/fpga"
)
const (
namespace = "fpga.intel.com"
resourceReplaceOp = `{
"op": "remove",
"path": "/spec/containers/%d/resources/%s/%s"
}, {
"op": "add",
"path": "/spec/containers/%d/resources/%s/%s",
"value": %s
}`
af = "af"
region = "region"
// "regiondevel" corresponds to the FPGA plugin's regiondevel mode. It requires
// FpgaRegion CRDs to be added to the cluster.
regiondevel = "regiondevel"
resourceRemoveOp = `{
"op": "remove",
"path": "/spec/containers/%d/resources/%s/%s"
@ -68,44 +66,49 @@ const (
var (
rfc6901Escaper = strings.NewReplacer("~", "~0", "/", "~1")
resourceRe = regexp.MustCompile(namespace + `/(?P<Region>[[:alnum:].]+)(-(?P<Af>[[:alnum:]]+))?`)
)
type patcher struct {
sync.Mutex
mode string
regionMap map[string]string
afMap map[string]string
resourceMap map[string]string
afMap map[string]*fpgav2.AcceleratorFunction
resourceMap map[string]string
resourceModeMap map[string]string
}
func newPatcher(mode string) (*patcher, error) {
if mode != preprogrammed && mode != orchestrated {
return nil, errors.Errorf("Unknown mode: %s", mode)
}
func newPatcher() *patcher {
return &patcher{
mode: mode,
regionMap: make(map[string]string),
afMap: make(map[string]string),
resourceMap: make(map[string]string),
}, nil
afMap: make(map[string]*fpgav2.AcceleratorFunction),
resourceMap: make(map[string]string),
resourceModeMap: make(map[string]string),
}
}
func (p *patcher) addAf(af *fpgav1.AcceleratorFunction) {
func (p *patcher) addAf(accfunc *fpgav2.AcceleratorFunction) error {
defer p.Unlock()
p.Lock()
p.afMap[af.Name] = af.Spec.AfuID
p.resourceMap[namespace+"/"+af.Name] = rfc6901Escaper.Replace(namespace + "/af-" + af.Spec.AfuID)
p.afMap[namespace+"/"+accfunc.Name] = accfunc
if accfunc.Spec.Mode == af {
devtype, err := fpga.GetAfuDevType(accfunc.Spec.InterfaceID, accfunc.Spec.AfuID)
if err != nil {
return err
}
p.resourceMap[namespace+"/"+accfunc.Name] = rfc6901Escaper.Replace(namespace + "/" + devtype)
} else {
p.resourceMap[namespace+"/"+accfunc.Name] = rfc6901Escaper.Replace(namespace + "/region-" + accfunc.Spec.InterfaceID)
}
p.resourceModeMap[namespace+"/"+accfunc.Name] = accfunc.Spec.Mode
return nil
}
func (p *patcher) addRegion(region *fpgav1.FpgaRegion) {
func (p *patcher) addRegion(region *fpgav2.FpgaRegion) {
defer p.Unlock()
p.Lock()
p.regionMap[region.Name] = region.Spec.InterfaceID
p.resourceModeMap[namespace+"/"+region.Name] = regiondevel
p.resourceMap[namespace+"/"+region.Name] = rfc6901Escaper.Replace(namespace + "/region-" + region.Spec.InterfaceID)
}
@ -113,149 +116,138 @@ func (p *patcher) removeAf(name string) {
defer p.Unlock()
p.Lock()
delete(p.afMap, name)
delete(p.afMap, namespace+"/"+name)
delete(p.resourceMap, namespace+"/"+name)
delete(p.resourceModeMap, namespace+"/"+name)
}
func (p *patcher) removeRegion(name string) {
defer p.Unlock()
p.Lock()
delete(p.regionMap, name)
delete(p.resourceMap, namespace+"/"+name)
delete(p.resourceModeMap, namespace+"/"+name)
}
// getRequestedResources validates the container's requirements first, then returns them as a map.
func getRequestedResources(container corev1.Container) (map[string]int64, error) {
for _, v := range container.Env {
if strings.HasPrefix(v.Name, "FPGA_REGION") || strings.HasPrefix(v.Name, "FPGA_AFU") {
return nil, errors.Errorf("environment variable '%s' is not allowed", v.Name)
}
}
// Container may happen to have Requests, but not Limits. Check Requests first,
// then in the next loop iterate over Limits.
for resourceName, resourceQuantity := range container.Resources.Requests {
rname := strings.ToLower(string(resourceName))
if !strings.HasPrefix(rname, namespace) {
// Skip non-FPGA resources in Requests.
continue
}
if container.Resources.Limits[resourceName] != resourceQuantity {
return nil, errors.Errorf(
"'limits' and 'requests' for %q must be equal as extended resources cannot be overcommitted",
rname)
}
}
resources := make(map[string]int64)
for resourceName, resourceQuantity := range container.Resources.Limits {
rname := strings.ToLower(string(resourceName))
if !strings.HasPrefix(rname, namespace) {
// Skip non-FPGA resources in Limits.
continue
}
if container.Resources.Requests[resourceName] != resourceQuantity {
return nil, errors.Errorf(
"'limits' and 'requests' for %q must be equal as extended resources cannot be overcommitted",
rname)
}
quantity, ok := resourceQuantity.AsInt64()
if !ok {
return nil, errors.Errorf("resource quantity isn't of integral type for %q", rname)
}
resources[rname] = quantity
}
return resources, nil
}
func (p *patcher) getPatchOps(containerIdx int, container corev1.Container) ([]string, error) {
switch p.mode {
case preprogrammed:
return p.getPatchOpsPreprogrammed(containerIdx, container)
case orchestrated:
return p.getPatchOpsOrchestrated(containerIdx, container)
}
return nil, errors.Errorf("Uknown mode: %s", p.mode)
}
func (p *patcher) getPatchOpsPreprogrammed(containerIdx int, container corev1.Container) ([]string, error) {
var ops []string
for resourceName, resourceQuantity := range container.Resources.Limits {
newName, err := p.translateFpgaResourceName(resourceName)
if err != nil {
return nil, err
}
if len(newName) > 0 {
op := fmt.Sprintf(resourceReplaceOp, containerIdx,
"limits", rfc6901Escaper.Replace(string(resourceName)),
containerIdx, "limits", newName, resourceQuantity.String())
ops = append(ops, op)
}
}
for resourceName, resourceQuantity := range container.Resources.Requests {
newName, err := p.translateFpgaResourceName(resourceName)
if err != nil {
return nil, err
}
if len(newName) > 0 {
op := fmt.Sprintf(resourceReplaceOp, containerIdx,
"requests", rfc6901Escaper.Replace(string(resourceName)),
containerIdx, "requests", newName, resourceQuantity.String())
ops = append(ops, op)
}
}
return ops, nil
}
func (p *patcher) translateFpgaResourceName(oldname corev1.ResourceName) (string, error) {
rname := strings.ToLower(string(oldname))
if !strings.HasPrefix(rname, namespace) {
return "", nil
requestedResources, err := getRequestedResources(container)
if err != nil {
return nil, err
}
defer p.Unlock()
p.Lock()
if newname, ok := p.resourceMap[rname]; ok {
return newname, nil
}
return "", errors.Errorf("Unknown FPGA resource: %s", rname)
}
func (p *patcher) checkResourceRequests(container corev1.Container) error {
for resourceName, resourceQuantity := range container.Resources.Requests {
interfaceID, _, err := p.parseResourceName(string(resourceName))
if err != nil {
return err
}
if interfaceID == "" {
// Skip non-FPGA resources
continue
}
if container.Resources.Limits[resourceName] != resourceQuantity {
return errors.Errorf("'limits' and 'requests' for %s must be equal", string(resourceName))
}
}
return nil
}
func (p *patcher) getPatchOpsOrchestrated(containerIdx int, container corev1.Container) ([]string, error) {
var ops []string
for _, v := range container.Env {
if strings.HasPrefix(v.Name, "FPGA_REGION") || strings.HasPrefix(v.Name, "FPGA_AFU") {
return nil, errors.Errorf("The environment variable '%s' is not allowed", v.Name)
}
}
if err := p.checkResourceRequests(container); err != nil {
return nil, err
}
regions := make(map[string]int64)
fpgaPluginMode := ""
resources := make(map[string]int64)
envVars := make(map[string]string)
counter := 0
for resourceName, resourceQuantity := range container.Resources.Limits {
interfaceID, afuID, err := p.parseResourceName(string(resourceName))
if err != nil {
return nil, err
for rname, quantity := range requestedResources {
mode, found := p.resourceModeMap[rname]
if !found {
return nil, errors.Errorf("no such resource: %q", rname)
}
if interfaceID == "" && afuID == "" {
// Skip non-FPGA resources
continue
switch mode {
case regiondevel:
// Do nothing.
// The requested resources are exposed by FPGA plugins working in "regiondevel" mode.
// In this mode the workload is supposed to program FPGA regions.
// A cluster admin has to add FpgaRegion CRDs to allow this.
case af:
// Do nothing.
// The requested resources are exposed by FPGA plugins working in "af" mode.
case region:
// Let fpga_crihook know how to program the regions by setting ENV variables.
// The requested resources are exposed by FPGA plugins working in "region" mode.
for i := int64(0); i < quantity; i++ {
counter++
envVars[fmt.Sprintf("FPGA_REGION_%d", counter)] = p.afMap[rname].Spec.InterfaceID
envVars[fmt.Sprintf("FPGA_AFU_%d", counter)] = p.afMap[rname].Spec.AfuID
}
default:
msg := fmt.Sprintf("%q is registered with unknown mode %q instead of %q or %q",
rname, p.resourceModeMap[rname], af, region)
// Let admin know about broken af CRD.
klog.Error(msg)
return nil, errors.New(msg)
}
if container.Resources.Requests[resourceName] != resourceQuantity {
return nil, errors.Errorf("'limits' and 'requests' for %s must be equal", string(resourceName))
if fpgaPluginMode == "" {
fpgaPluginMode = mode
} else if fpgaPluginMode != mode {
return nil, errors.New("container cannot be scheduled as it requires resources operated in different modes")
}
quantity, ok := resourceQuantity.AsInt64()
if !ok {
return nil, errors.New("Resource quantity isn't of integral type")
}
regions[interfaceID] = regions[interfaceID] + quantity
mappedName := p.resourceMap[rname]
resources[mappedName] = resources[mappedName] + quantity
for i := int64(0); i < quantity; i++ {
counter++
envVars[fmt.Sprintf("FPGA_REGION_%d", counter)] = interfaceID
envVars[fmt.Sprintf("FPGA_AFU_%d", counter)] = afuID
}
ops = append(ops, fmt.Sprintf(resourceRemoveOp, containerIdx, "limits", rfc6901Escaper.Replace(string(resourceName))))
ops = append(ops, fmt.Sprintf(resourceRemoveOp, containerIdx, "requests", rfc6901Escaper.Replace(string(resourceName))))
// Add operations to remove unresolved resources from the pod.
ops = append(ops, fmt.Sprintf(resourceRemoveOp, containerIdx, "limits", rfc6901Escaper.Replace(rname)))
ops = append(ops, fmt.Sprintf(resourceRemoveOp, containerIdx, "requests", rfc6901Escaper.Replace(rname)))
}
for interfaceID, quantity := range regions {
op := fmt.Sprintf(resourceAddOp, containerIdx, "limits", rfc6901Escaper.Replace(namespace+"/region-"+interfaceID), quantity)
// Add operations to add resolved resources to the pod.
for resource, quantity := range resources {
op := fmt.Sprintf(resourceAddOp, containerIdx, "limits", resource, quantity)
ops = append(ops, op)
op = fmt.Sprintf(resourceAddOp, containerIdx, "requests", rfc6901Escaper.Replace(namespace+"/region-"+interfaceID), quantity)
op = fmt.Sprintf(resourceAddOp, containerIdx, "requests", resource, quantity)
ops = append(ops, op)
}
// Add the ENV variables to the pod if needed.
if len(envVars) > 0 {
for _, envvar := range container.Env {
envVars[envvar.Name] = envvar.Value
@ -276,69 +268,21 @@ func (p *patcher) getPatchOpsOrchestrated(containerIdx int, container corev1.Con
return ops, nil
}
func (p *patcher) parseResourceName(input string) (string, string, error) {
var interfaceID, afuID string
var regionName, afName string
var ok bool
result := resourceRe.FindStringSubmatch(input)
if result == nil {
return "", "", nil
}
defer p.Unlock()
p.Lock()
for num, group := range resourceRe.SubexpNames() {
switch group {
case "Region":
regionName = result[num]
if interfaceID, ok = p.regionMap[result[num]]; !ok {
return "", "", errors.Errorf("Unknown region name: %s", result[num])
}
case "Af":
afName = result[num]
}
}
if afName != "" {
if afuID, ok = p.afMap[regionName+"-"+afName]; !ok {
return "", "", errors.Errorf("Unknown AF name: %s", regionName+"-"+afName)
}
}
return interfaceID, afuID, nil
}
// patcherManager keeps track of patchers registered for different Kubernetes namespaces.
type patcherManager struct {
defaultMode string
patchers map[string]*patcher
type patcherManager map[string]*patcher
func newPatcherManager() patcherManager {
return make(map[string]*patcher)
}
func newPatcherManager(defaultMode string) (*patcherManager, error) {
if defaultMode != preprogrammed && defaultMode != orchestrated {
return nil, errors.Errorf("Unknown mode: %s", defaultMode)
func (pm patcherManager) getPatcher(namespace string) *patcher {
if p, ok := pm[namespace]; ok {
return p
}
return &patcherManager{
defaultMode: defaultMode,
patchers: make(map[string]*patcher),
}, nil
}
func (pm *patcherManager) getPatcher(namespace string) (*patcher, error) {
if p, ok := pm.patchers[namespace]; ok {
return p, nil
}
p, err := newPatcher(pm.defaultMode)
if err != nil {
return nil, err
}
pm.patchers[namespace] = p
p := newPatcher()
pm[namespace] = p
klog.V(4).Info("created new patcher for namespace", namespace)
return p, nil
return p
}

View File

@ -21,9 +21,8 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
fpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
)
func init() {
@ -31,203 +30,68 @@ func init() {
}
func TestPatcherStorageFunctions(t *testing.T) {
af := &fpgav1.AcceleratorFunction{
af := &fpgav2.AcceleratorFunction{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0",
},
Spec: fpgav1.AcceleratorFunctionSpec{
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
},
}
region := &fpgav1.FpgaRegion{
region := &fpgav2.FpgaRegion{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10",
},
Spec: fpgav1.FpgaRegionSpec{
Spec: fpgav2.FpgaRegionSpec{
InterfaceID: "ce48969398f05f33946d560708be108a",
},
}
p, err := newPatcher(preprogrammed)
if err != nil {
t.Fatal(err)
}
p := newPatcher()
p.addAf(af)
if len(p.afMap) != 1 || len(p.resourceMap) != 1 {
if len(p.resourceModeMap) != 1 || len(p.afMap) != 1 || len(p.resourceMap) != 1 {
t.Error("Failed to add AF to patcher")
}
p.removeAf(af.Name)
if len(p.afMap) != 0 || len(p.resourceMap) != 0 {
if len(p.resourceModeMap) != 0 || len(p.afMap) != 0 || len(p.resourceMap) != 0 {
t.Error("Failed to remove AF from patcher")
}
p.addRegion(region)
if len(p.regionMap) != 1 || len(p.resourceMap) != 1 {
if len(p.resourceModeMap) != 1 || len(p.resourceMap) != 1 {
t.Error("Failed to add fpga region to patcher")
}
p.removeRegion(region.Name)
if len(p.regionMap) != 0 || len(p.resourceMap) != 0 {
if len(p.resourceModeMap) != 0 || len(p.resourceMap) != 0 {
t.Error("Failed to remove fpga region from patcher")
}
}
func TestGetPatchOpsPreprogrammed(t *testing.T) {
func TestGetPatchOps(t *testing.T) {
tcases := []struct {
name string
resourceMap map[string]string
container corev1.Container
afs []*fpgav2.AcceleratorFunction
regions []*fpgav2.FpgaRegion
expectedErr bool
expectedOps int
}{
{
name: "Empty container",
},
{
name: "Unknown resource in limits",
name: "Successful handling for region mode",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-unknown": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
},
},
},
expectedErr: true,
},
{
name: "Unknown resource in requests",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-unknown": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
},
},
},
expectedErr: true,
},
{
name: "Successful case",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb0-alias": resource.MustParse("2"),
"cpu": resource.MustParse("1"),
},
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
},
},
},
resourceMap: map[string]string{
"fpga.intel.com/arria10-nlb0": rfc6901Escaper.Replace("fpga.intel.com/af-d8424dc4a4a3c413f89e433683f9040b"),
},
expectedOps: 2,
},
}
for _, tt := range tcases {
p := &patcher{
resourceMap: tt.resourceMap,
}
ops, err := p.getPatchOpsPreprogrammed(0, tt.container)
if tt.expectedErr && err == nil {
t.Errorf("Test case '%s': no error returned", tt.name)
}
if !tt.expectedErr && err != nil {
t.Errorf("Test case '%s': unexpected error %v", tt.name, err)
}
if len(ops) != tt.expectedOps {
t.Errorf("test case '%s': expected %d ops, but got %d\n%v", tt.name, tt.expectedOps, len(ops), ops)
}
}
}
func TestParseResourceName(t *testing.T) {
tcases := []struct {
input string
interfaceID string
afuID string
afMap map[string]string
regionMap map[string]string
expectedErr bool
}{
{
input: "fpga.intel.com/arria10",
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
interfaceID: "ce48969398f05f33946d560708be108a",
},
{
input: "fpga.intel.com/arria10-unknown",
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
expectedErr: true,
},
{
input: "fpga.intel.com/unknown",
expectedErr: true,
},
{
input: "fpga.example.com/something",
},
{
input: "fpga.intel.com/arria10-nlb0",
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
afMap: map[string]string{
"arria10-nlb0": "d8424dc4a4a3c413f89e433683f9040b",
},
interfaceID: "ce48969398f05f33946d560708be108a",
afuID: "d8424dc4a4a3c413f89e433683f9040b",
},
}
for num, tt := range tcases {
p := &patcher{
afMap: tt.afMap,
regionMap: tt.regionMap,
}
interfaceID, afuID, err := p.parseResourceName(tt.input)
if tt.expectedErr {
if err != nil {
continue
} else {
t.Errorf("In case %d we didn't get error", num)
}
}
if tt.interfaceID != interfaceID || tt.afuID != afuID {
t.Errorf("In case %d expected (%s, %s), but got (%s, %s)", num, tt.interfaceID, tt.afuID, interfaceID, afuID)
}
}
}
func TestGetPatchOpsOrchestrated(t *testing.T) {
tcases := []struct {
name string
container corev1.Container
afMap map[string]string
regionMap map[string]string
expectedErr bool
expectedOps int
}{
{
name: "Successful handling",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
},
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb0-alias": resource.MustParse("2"),
"cpu": resource.MustParse("3"),
},
},
Env: []corev1.EnvVar{
@ -237,13 +101,79 @@ func TestGetPatchOpsOrchestrated(t *testing.T) {
},
},
},
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
afs: []*fpgav2.AcceleratorFunction{
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0",
},
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
InterfaceID: "ce48969398f05f33946d560708be108a",
Mode: region,
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0-alias",
},
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
InterfaceID: "ce48969398f05f33946d560708be108a",
Mode: region,
},
},
},
afMap: map[string]string{
"arria10-nlb0": "d8424dc4a4a3c413f89e433683f9040b",
expectedOps: 7,
},
{
name: "Successful handling for af mode",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
},
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
},
},
},
expectedOps: 5,
afs: []*fpgav2.AcceleratorFunction{
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0",
},
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
InterfaceID: "ce48969398f05f33946d560708be108a",
Mode: af,
},
},
},
expectedOps: 4,
},
{
name: "Successful handling for regiondevel mode",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10": resource.MustParse("1"),
},
Requests: corev1.ResourceList{
"fpga.intel.com/arria10": resource.MustParse("1"),
},
},
},
regions: []*fpgav2.FpgaRegion{
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10",
},
Spec: fpgav2.FpgaRegionSpec{
InterfaceID: "ce48969398f05f33946d560708be108a",
},
},
},
expectedOps: 4,
},
{
name: "Unequal FPGA resources in Limits and Requests 1",
@ -255,13 +185,6 @@ func TestGetPatchOpsOrchestrated(t *testing.T) {
},
},
},
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
afMap: map[string]string{
"arria10-nlb0": "d8424dc4a4a3c413f89e433683f9040b",
"arria10-nlb3": "f7df405cbd7acf7222f144b0b93acd18",
},
expectedErr: true,
},
{
@ -270,45 +193,19 @@ func TestGetPatchOpsOrchestrated(t *testing.T) {
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb3": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb3": resource.MustParse("2"),
},
},
},
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
afMap: map[string]string{
"arria10-nlb0": "d8424dc4a4a3c413f89e433683f9040b",
"arria10-nlb3": "f7df405cbd7acf7222f144b0b93acd18",
},
expectedErr: true,
},
{
name: "Unknown FPGA model in Requests",
name: "Unknown FPGA resources in container requirements",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"fpga.intel.com/unknown-nlb0": resource.MustParse("1"),
},
},
},
expectedErr: true,
},
{
name: "Unknown AFU in Requests",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-unknown": resource.MustParse("1"),
},
},
},
expectedErr: true,
},
{
name: "Unknown FPGA model in Limits",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/unknown-nlb0": resource.MustParse("1"),
},
@ -316,23 +213,12 @@ func TestGetPatchOpsOrchestrated(t *testing.T) {
},
expectedErr: true,
},
{
name: "Unknown AFU in Limits",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-unknown": resource.MustParse("1"),
},
},
},
expectedErr: true,
},
{
name: "Wrong ENV",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"cpu": resource.MustParse("1"),
},
},
Env: []corev1.EnvVar{
@ -342,12 +228,6 @@ func TestGetPatchOpsOrchestrated(t *testing.T) {
},
},
},
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
},
afMap: map[string]string{
"arria10-nlb0": "d8424dc4a4a3c413f89e433683f9040b",
},
expectedErr: true,
},
{
@ -362,59 +242,119 @@ func TestGetPatchOpsOrchestrated(t *testing.T) {
},
},
},
regionMap: map[string]string{
"arria10": "ce48969398f05f33946d560708be108a",
expectedErr: true,
},
{
name: "Require resources operated in af and region modes",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb3": resource.MustParse("2"),
"cpu": resource.MustParse("1"),
},
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
"fpga.intel.com/arria10-nlb3": resource.MustParse("2"),
"cpu": resource.MustParse("3"),
},
},
},
afMap: map[string]string{
"arria10-nlb0": "d8424dc4a4a3c413f89e433683f9040b",
afs: []*fpgav2.AcceleratorFunction{
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0",
},
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
InterfaceID: "ce48969398f05f33946d560708be108a",
Mode: region,
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb3",
},
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
InterfaceID: "f7df405cbd7acf7222f144b0b93acd18",
Mode: af,
},
},
},
expectedErr: true,
},
{
name: "Unknown mode",
container: corev1.Container{
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
},
Requests: corev1.ResourceList{
"fpga.intel.com/arria10-nlb0": resource.MustParse("1"),
},
},
},
afs: []*fpgav2.AcceleratorFunction{
{
ObjectMeta: metav1.ObjectMeta{
Name: "arria10-nlb0",
},
Spec: fpgav2.AcceleratorFunctionSpec{
AfuID: "d8424dc4a4a3c413f89e433683f9040b",
InterfaceID: "ce48969398f05f33946d560708be108a",
Mode: "unknown",
},
},
},
expectedErr: true,
},
}
for _, tt := range tcases {
p := &patcher{
afMap: tt.afMap,
regionMap: tt.regionMap,
}
klog.V(4).Info(tt.name)
ops, err := p.getPatchOpsOrchestrated(0, tt.container)
if tt.expectedErr && err == nil {
t.Errorf("Test case '%s': no error returned", tt.name)
}
if !tt.expectedErr && err != nil {
t.Errorf("Test case '%s': unexpected error %+v", tt.name, err)
}
if len(ops) != tt.expectedOps {
t.Errorf("test case '%s': expected %d ops, but got %d\n%v", tt.name, tt.expectedOps, len(ops), ops)
}
}
}
func TestNewPatcherManager(t *testing.T) {
tcases := []struct {
name string
defaultMode string
expectedErr bool
}{
{
name: "Everything is OK",
defaultMode: preprogrammed,
},
{
name: "Unknown default mode",
defaultMode: "unknownMode",
expectedErr: true,
},
}
for _, tt := range tcases {
t.Run(tt.name, func(t *testing.T) {
_, err := newPatcherManager(tt.defaultMode)
p := newPatcher()
for _, af := range tt.afs {
p.addAf(af)
}
for _, region := range tt.regions {
p.addRegion(region)
}
ops, err := p.getPatchOps(0, tt.container)
if tt.expectedErr && err == nil {
t.Errorf("Test case '%s': no error returned", tt.name)
}
if !tt.expectedErr && err != nil {
t.Errorf("Test case '%s': unexpected error %+v", tt.name, err)
t.Errorf("Test case '%s': unexpected error: %+v", tt.name, err)
}
if len(ops) != tt.expectedOps {
t.Errorf("test case '%s': expected %d ops, but got %d\n%v", tt.name, tt.expectedOps, len(ops), ops)
}
})
}
}
func TestGetPatcher(t *testing.T) {
namespace := "test"
tcases := []struct {
name string
pm patcherManager
}{
{
name: "Create new patcher",
pm: newPatcherManager(),
},
{
name: "Return existing patcher",
pm: map[string]*patcher{namespace: newPatcher()},
},
}
for _, tt := range tcases {
t.Run(tt.name, func(t *testing.T) {
p := tt.pm.getPatcher(namespace)
if p != tt.pm[namespace] {
t.Error("stored and received patchers are not equal")
}
})
}

View File

@ -12,7 +12,7 @@
* [Verify node kubelet config](#verify-node-kubelet-config)
* [Deploying as a DaemonSet](#deploying-as-a-daemonset)
* [Create a service account](#create-a-service-account)
* [Deploying `orchestrated` mode](#deploying-orchestrated-mode)
* [Deploying `region` mode](#deploying-region-mode)
* [Deploying `af` mode](#deploying-af-mode)
* [Deploy the DaemonSet](#deploy-the-daemonset)
* [Verify plugin registration](#verify-plugin-registration)
@ -75,26 +75,26 @@ development, initial deployment and debugging.
The FPGA plugin set can run in one of two modes:
- `region`/`orchestrated` mode, where the plugins locate and advertise
- `region` mode, where the plugins locate and advertise
regions of the FPGA, and facilitate programing of those regions with the
requested bistreams.
- `af`/`preprogrammed` mode, where the FPGA bitstreams are already loaded
- `af` mode, where the FPGA bitstreams are already loaded
onto the FPGA, and the plugins discover and advertises the existing
Accelerator Functions (AF).
The example YAML deployments described in this document only currently support
`af`/`preprogrammed` mode. To utilise `region`/`orchestrated` mode, either modify
the existing YAML appropriately, or deploy 'by hand'.
`af` mode. To utilise `region` mode, either modify the existing YAML appropriately,
or deploy 'by hand'.
Overview diagrams of `preprogrammed` and `orchestrated` modes are below:
Overview diagrams of `af` and `region` modes are below:
Orchestrated/region mode:
region mode:
![Overview of `orchestrated` mode](pictures/FPGA-orchestrated.png)
![Overview of `region` mode](pictures/FPGA-region.png)
Preprogrammed/af mode:
af mode:
![Overview of `preprogrammed` mode](pictures/FPGA-preprogrammed.png)
![Overview of `af` mode](pictures/FPGA-af.png)
# Installation
@ -136,12 +136,11 @@ major components:
- [FPGA admission controller webhook](../fpga_admissionwebhook/README.md)
- [FPGA prestart CRI-O hook](../fpga_crihook/README.md)
The CRI-O hook is only *required* if `orchestrated` FPGA bitstream programming mode is
being used, but is installed by default by the
The CRI-O hook is only *required* if `region` mode is being used, but is installed by default by the
[FPGA plugin DaemonSet YAML](../../deployments/fpga_plugin/fpga_plugin.yaml), and is benign
in `preprogrammed` mode.
in `af` mode.
If using the `preprogrammed` mode, and therefore *not* using the
If using the `af` mode, and therefore *not* using the
CRI-O prestart hook, runtimes other than CRI-O can be used (that is, the CRI-O hook presently
*only* works with the CRI-O runtime).
@ -192,8 +191,8 @@ YAML deployment files to reference your required image.
### For beta testing: new deployment model
The FPGA plugin deployment is currently being rewritten to enable
straight-forward deployment of both `af/preprogrammed` and
`region/orchestrated` modes. The deployment has two steps:
straight-forward deployment of both `af` and
`region` modes. The deployment has two steps:
1. Run `scripts/fpga-plugin-prepare-for-kustomization.sh`. This will
create the necessary secrets: a key and a signed certificate for
@ -226,19 +225,16 @@ clusterrole.rbac.authorization.k8s.io/node-getter created
clusterrolebinding.rbac.authorization.k8s.io/get-nodes created
```
### Deploying `orchestrated` mode
### Deploying `region` mode
To deploy the FPGA plugin DaemonSet in `orchestrated` (`region`) mode, you need to set the plugin
To deploy the FPGA plugin DaemonSet in `region` mode, you need to set the plugin
mode annotation on all of your nodes, otherwise the FPGA plugin will run in its default
`af` (`preprogrammed`) mode.
`af` mode.
```bash
$ kubectl annotate node --all 'fpga.intel.com/device-plugin-mode=region'
```
Mixing of the two modes (`orchestrated` and `af`) across nodes in the same cluster is
*not currently supported*.
### Deploying `af` mode
To deploy the FPGA plugin DaemonSet in `af` mode, you do not need to set the mode annotation on
@ -260,7 +256,7 @@ daemonset.apps/intel-fpga-plugin created
### Verify plugin registration
Verify the FPGA plugin has been deployed on the nodes. The below shows the output
you can expect in `region` mode, but similar output should be expected for `preprogrammed`
you can expect in `region` mode, but similar output should be expected for `af`
mode:
```bash

View File

@ -116,7 +116,7 @@ func getDevicesDFL() []device {
},
{
id: "dfl-port.4",
afuID: "d8424dc4a4a3c413f89e433683f9040b",
afuID: unhealthyAfuID,
devNode: "/dev/dfl-port.4",
},
},
@ -240,7 +240,7 @@ func TestGetAfuTreeDFL(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-d8424dc4a4a3c413f89e433683f9040b", "dfl-port.0", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
expected.AddDevice("af-ce4.d84.zkiWk5jwXzOUbVYHCL4QithCTcSko8QT-J5DNoP5BAs", "dfl-port.0", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
nodes = []pluginapi.DeviceSpec{
{
@ -250,7 +250,7 @@ func TestGetAfuTreeDFL(t *testing.T) {
},
}
expected.AddDevice(afMode+"-d8424dc4a4a3c413f89e433683f9040b", "dfl-port.1", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
expected.AddDevice("af-ce4.d84.zkiWk5jwXzOUbVYHCL4QithCTcSko8QT-J5DNoP5BAs", "dfl-port.1", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
nodes = []pluginapi.DeviceSpec{
{
@ -259,7 +259,7 @@ func TestGetAfuTreeDFL(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-d8424dc4a4a3c413f89e433683f9040b", "dfl-port.2", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
expected.AddDevice("af-ce4.d84.zkiWk5jwXzOUbVYHCL4QithCTcSko8QT-J5DNoP5BAs", "dfl-port.2", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
nodes = []pluginapi.DeviceSpec{
{
@ -268,7 +268,7 @@ func TestGetAfuTreeDFL(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-"+unhealthyAfuID, "dfl-port.3", dpapi.NewDeviceInfo(pluginapi.Unhealthy, nodes, nil, nil))
expected.AddDevice("af-fff.fff.__________________________________________8", "dfl-port.3", dpapi.NewDeviceInfo(pluginapi.Unhealthy, nodes, nil, nil))
nodes = []pluginapi.DeviceSpec{
{
@ -277,11 +277,11 @@ func TestGetAfuTreeDFL(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-d8424dc4a4a3c413f89e433683f9040b", "dfl-port.4", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
expected.AddDevice("af-fff.fff.__________________________________________8", "dfl-port.4", dpapi.NewDeviceInfo(pluginapi.Unhealthy, nodes, nil, nil))
result := getAfuTree(getDevicesDFL())
if !reflect.DeepEqual(result, expected) {
t.Errorf("Got unexpected result: %v, expected: %v", result, expected)
t.Errorf("Got unexpected result:\n%v\nexpected:\n%v", result, expected)
}
}

View File

@ -28,6 +28,7 @@ import (
pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
dpapi "github.com/intel/intel-device-plugins-for-kubernetes/pkg/deviceplugin"
"github.com/intel/intel-device-plugins-for-kubernetes/pkg/fpga"
"github.com/pkg/errors"
)
@ -125,7 +126,11 @@ func getAfuTree(devices []device) dpapi.DeviceTree {
if afu.afuID == unhealthyAfuID {
health = pluginapi.Unhealthy
}
devType := fmt.Sprintf("%s-%s", afMode, afu.afuID)
devType, err := fpga.GetAfuDevType(region.interfaceID, afu.afuID)
if err != nil {
klog.Warningf("failed to get devtype: %+v", err)
continue
}
devNodes := []pluginapi.DeviceSpec{
{
HostPath: afu.devNode,

View File

@ -210,7 +210,7 @@ func TestGetAfuTreeOPAE(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-d8424dc4a4a3c413f89e433683f9040b", "intel-fpga-port.0", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
expected.AddDevice("af-ce4.d84.zkiWk5jwXzOUbVYHCL4QithCTcSko8QT-J5DNoP5BAs", "intel-fpga-port.0", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
nodes = []pluginapi.DeviceSpec{
{
@ -219,7 +219,7 @@ func TestGetAfuTreeOPAE(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-d8424dc4a4a3c413f89e433683f9040b", "intel-fpga-port.1", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
expected.AddDevice("af-ce4.d84.zkiWk5jwXzOUbVYHCL4QithCTcSko8QT-J5DNoP5BAs", "intel-fpga-port.1", dpapi.NewDeviceInfo(pluginapi.Healthy, nodes, nil, nil))
nodes = []pluginapi.DeviceSpec{
{
@ -228,7 +228,7 @@ func TestGetAfuTreeOPAE(t *testing.T) {
Permissions: "rw",
},
}
expected.AddDevice(afMode+"-"+unhealthyAfuID, "intel-fpga-port.2", dpapi.NewDeviceInfo(pluginapi.Unhealthy, nodes, nil, nil))
expected.AddDevice("af-fff.fff.__________________________________________8", "intel-fpga-port.2", dpapi.NewDeviceInfo(pluginapi.Unhealthy, nodes, nil, nil))
result := getAfuTree(getDevicesOPAE())
if !reflect.DeepEqual(result, expected) {

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -4,7 +4,7 @@ metadata:
name: acceleratorfunctions.fpga.intel.com
spec:
group: fpga.intel.com
version: v1
version: v2
scope: Namespaced
names:
plural: acceleratorfunctions
@ -19,4 +19,10 @@ spec:
properties:
afuId:
type: string
pattern: '^[0-9a-f]{8,128}$'
pattern: '^[0-9a-f]{8,32}$'
interfaceId:
type: string
pattern: '^[0-9a-f]{8,32}$'
mode:
type: string
pattern: '^af|region$'

View File

@ -1,19 +1,12 @@
# DCP 1.0
apiVersion: fpga.intel.com/v1
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.0-compress
spec:
afuId: 946c21d1e49704a5e5daa0805bc6b0785e1765bf
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.0-nlb0
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.0-nlb3
@ -21,14 +14,14 @@ spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
---
# DCP 1.1
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.1-nlb0
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.1-nlb3
@ -36,14 +29,14 @@ spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
---
# DCP 1.2
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.2-nlb0
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.2-nlb3
@ -51,14 +44,14 @@ spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
---
# D5005
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: d5005-nlb0
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: d5005-nlb3

View File

@ -1,5 +1,5 @@
# DCP 1.0
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: arria10.dcp1.0
@ -7,7 +7,7 @@ spec:
interfaceId: ce48969398f05f33946d560708be108a
---
# DCP 1.1
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: arria10.dcp1.1
@ -15,7 +15,7 @@ spec:
interfaceId: 9926ab6d6c925a68aabca7d84c545738
---
# DCP 1.2
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: arria10.dcp1.2
@ -23,7 +23,7 @@ spec:
interfaceId: 69528db6eb31577a8c3668f9faa081f6
---
# D5005
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: d5005

View File

@ -29,7 +29,6 @@ spec:
args:
- -tls-cert-file=/etc/webhook/certs/cert.pem
- -tls-private-key-file=/etc/webhook/certs/key.pem
- -mode={MODE}
- -v=1
volumeMounts:
- name: webhook-certs

View File

@ -1,94 +1,121 @@
# DCP 1.0
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: arria10.dcp1.0
spec:
interfaceId: ce48969398f05f33946d560708be108a
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.0-compress
spec:
afuId: 946c21d1e49704a5e5daa0805bc6b0785e1765bf
---
apiVersion: fpga.intel.com/v1
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.0-nlb0
name: arria10.dcp1.0-nlb0-orchestrated
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
interfaceId: ce48969398f05f33946d560708be108a
mode: region
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.0-nlb3
name: arria10.dcp1.0-nlb3-orchestrated
spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
interfaceId: ce48969398f05f33946d560708be108a
mode: region
---
# DCP 1.1
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: arria10.dcp1.1
spec:
interfaceId: 9926ab6d6c925a68aabca7d84c545738
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.1-nlb0
name: arria10.dcp1.1-nlb0-orchestrated
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
interfaceId: 9926ab6d6c925a68aabca7d84c545738
mode: region
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.1-nlb3
name: arria10.dcp1.1-nlb3-orchestrated
spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
interfaceId: 9926ab6d6c925a68aabca7d84c545738
mode: region
---
# DCP 1.2
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: arria10.dcp1.2
spec:
interfaceId: 69528db6eb31577a8c3668f9faa081f6
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.2-nlb0
name: arria10.dcp1.2-nlb0-orchestrated
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
interfaceId: 69528db6eb31577a8c3668f9faa081f6
mode: region
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.2-nlb3
name: arria10.dcp1.2-nlb0-preprogrammed
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
interfaceId: 69528db6eb31577a8c3668f9faa081f6
mode: af
---
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: arria10.dcp1.2-nlb3-orchestrated
spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
interfaceId: 69528db6eb31577a8c3668f9faa081f6
mode: region
---
# D5005
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: FpgaRegion
metadata:
name: d5005
spec:
interfaceId: bfac4d851ee856fe8c95865ce1bbaa2d
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: d5005-nlb0
name: d5005-nlb0-orchestrated
spec:
afuId: d8424dc4a4a3c413f89e433683f9040b
interfaceId: bfac4d851ee856fe8c95865ce1bbaa2d
mode: region
---
apiVersion: fpga.intel.com/v1
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: d5005-nlb3
name: d5005-nlb3-orchestrated
spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
interfaceId: bfac4d851ee856fe8c95865ce1bbaa2d
mode: region
---
apiVersion: fpga.intel.com/v2
kind: AcceleratorFunction
metadata:
name: d5005-nlb3-preprogrammed
spec:
afuId: f7df405cbd7acf7222f144b0b93acd18
interfaceId: bfac4d851ee856fe8c95865ce1bbaa2d
mode: af

View File

@ -4,7 +4,7 @@ metadata:
name: fpgaregions.fpga.intel.com
spec:
group: fpga.intel.com
version: v1
version: v2
scope: Namespaced
names:
plural: fpgaregions
@ -19,4 +19,4 @@ spec:
properties:
interfaceId:
type: string
pattern: '^[0-9a-f]{8,128}$'
pattern: '^[0-9a-f]{8,32}$'

View File

@ -2,4 +2,4 @@
// +groupName=fpga.intel.com
package v1
package v2

View File

@ -1,4 +1,4 @@
package v1
package v2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -9,7 +9,7 @@ import (
)
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: fpgaintel.GroupName, Version: "v1"}
var SchemeGroupVersion = schema.GroupVersion{Group: fpgaintel.GroupName, Version: "v2"}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {

View File

@ -1,4 +1,4 @@
package v1
package v2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -18,7 +18,9 @@ type AcceleratorFunction struct {
// AcceleratorFunctionSpec contains actual specs for AcceleratorFunction
type AcceleratorFunctionSpec struct {
AfuID string `json:"afuId"`
AfuID string `json:"afuId"`
InterfaceID string `json:"interfaceId"`
Mode string `json:"mode"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -16,7 +16,7 @@
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1
package v2
import (
runtime "k8s.io/apimachinery/pkg/runtime"

View File

@ -19,7 +19,7 @@ package versioned
import (
"fmt"
fpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v1"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v2"
discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest"
flowcontrol "k8s.io/client-go/util/flowcontrol"
@ -27,19 +27,19 @@ import (
type Interface interface {
Discovery() discovery.DiscoveryInterface
FpgaV1() fpgav1.FpgaV1Interface
FpgaV2() fpgav2.FpgaV2Interface
}
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
fpgaV1 *fpgav1.FpgaV1Client
fpgaV2 *fpgav2.FpgaV2Client
}
// FpgaV1 retrieves the FpgaV1Client
func (c *Clientset) FpgaV1() fpgav1.FpgaV1Interface {
return c.fpgaV1
// FpgaV2 retrieves the FpgaV2Client
func (c *Clientset) FpgaV2() fpgav2.FpgaV2Interface {
return c.fpgaV2
}
// Discovery retrieves the DiscoveryClient
@ -63,7 +63,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
}
var cs Clientset
var err error
cs.fpgaV1, err = fpgav1.NewForConfig(&configShallowCopy)
cs.fpgaV2, err = fpgav2.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
@ -79,7 +79,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.fpgaV1 = fpgav1.NewForConfigOrDie(c)
cs.fpgaV2 = fpgav2.NewForConfigOrDie(c)
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
return &cs
@ -88,7 +88,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
// New creates a new Clientset for the given RESTClient.
func New(c rest.Interface) *Clientset {
var cs Clientset
cs.fpgaV1 = fpgav1.New(c)
cs.fpgaV2 = fpgav2.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &cs

View File

@ -18,8 +18,8 @@ package fake
import (
clientset "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned"
fpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v1"
fakefpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v1/fake"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v2"
fakefpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v2/fake"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery"
@ -74,7 +74,7 @@ func (c *Clientset) Tracker() testing.ObjectTracker {
var _ clientset.Interface = &Clientset{}
// FpgaV1 retrieves the FpgaV1Client
func (c *Clientset) FpgaV1() fpgav1.FpgaV1Interface {
return &fakefpgav1.FakeFpgaV1{Fake: &c.Fake}
// FpgaV2 retrieves the FpgaV2Client
func (c *Clientset) FpgaV2() fpgav2.FpgaV2Interface {
return &fakefpgav2.FakeFpgaV2{Fake: &c.Fake}
}

View File

@ -17,7 +17,7 @@
package fake
import (
fpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@ -29,7 +29,7 @@ var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
fpgav1.AddToScheme,
fpgav2.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition

View File

@ -17,7 +17,7 @@
package scheme
import (
fpgav1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@ -29,7 +29,7 @@ var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
fpgav1.AddToScheme,
fpgav2.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition

View File

@ -14,15 +14,15 @@
// Code generated by client-gen. DO NOT EDIT.
package v1
package v2
import (
"context"
"time"
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
scheme "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/scheme"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
@ -36,14 +36,14 @@ type AcceleratorFunctionsGetter interface {
// AcceleratorFunctionInterface has methods to work with AcceleratorFunction resources.
type AcceleratorFunctionInterface interface {
Create(ctx context.Context, acceleratorFunction *v1.AcceleratorFunction, opts metav1.CreateOptions) (*v1.AcceleratorFunction, error)
Update(ctx context.Context, acceleratorFunction *v1.AcceleratorFunction, opts metav1.UpdateOptions) (*v1.AcceleratorFunction, error)
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.AcceleratorFunction, error)
List(ctx context.Context, opts metav1.ListOptions) (*v1.AcceleratorFunctionList, error)
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.AcceleratorFunction, err error)
Create(ctx context.Context, acceleratorFunction *v2.AcceleratorFunction, opts v1.CreateOptions) (*v2.AcceleratorFunction, error)
Update(ctx context.Context, acceleratorFunction *v2.AcceleratorFunction, opts v1.UpdateOptions) (*v2.AcceleratorFunction, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v2.AcceleratorFunction, error)
List(ctx context.Context, opts v1.ListOptions) (*v2.AcceleratorFunctionList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.AcceleratorFunction, err error)
AcceleratorFunctionExpansion
}
@ -54,7 +54,7 @@ type acceleratorFunctions struct {
}
// newAcceleratorFunctions returns a AcceleratorFunctions
func newAcceleratorFunctions(c *FpgaV1Client, namespace string) *acceleratorFunctions {
func newAcceleratorFunctions(c *FpgaV2Client, namespace string) *acceleratorFunctions {
return &acceleratorFunctions{
client: c.RESTClient(),
ns: namespace,
@ -62,8 +62,8 @@ func newAcceleratorFunctions(c *FpgaV1Client, namespace string) *acceleratorFunc
}
// Get takes name of the acceleratorFunction, and returns the corresponding acceleratorFunction object, and an error if there is any.
func (c *acceleratorFunctions) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.AcceleratorFunction, err error) {
result = &v1.AcceleratorFunction{}
func (c *acceleratorFunctions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2.AcceleratorFunction, err error) {
result = &v2.AcceleratorFunction{}
err = c.client.Get().
Namespace(c.ns).
Resource("acceleratorfunctions").
@ -75,12 +75,12 @@ func (c *acceleratorFunctions) Get(ctx context.Context, name string, options met
}
// List takes label and field selectors, and returns the list of AcceleratorFunctions that match those selectors.
func (c *acceleratorFunctions) List(ctx context.Context, opts metav1.ListOptions) (result *v1.AcceleratorFunctionList, err error) {
func (c *acceleratorFunctions) List(ctx context.Context, opts v1.ListOptions) (result *v2.AcceleratorFunctionList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1.AcceleratorFunctionList{}
result = &v2.AcceleratorFunctionList{}
err = c.client.Get().
Namespace(c.ns).
Resource("acceleratorfunctions").
@ -92,7 +92,7 @@ func (c *acceleratorFunctions) List(ctx context.Context, opts metav1.ListOptions
}
// Watch returns a watch.Interface that watches the requested acceleratorFunctions.
func (c *acceleratorFunctions) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
func (c *acceleratorFunctions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
@ -107,8 +107,8 @@ func (c *acceleratorFunctions) Watch(ctx context.Context, opts metav1.ListOption
}
// Create takes the representation of a acceleratorFunction and creates it. Returns the server's representation of the acceleratorFunction, and an error, if there is any.
func (c *acceleratorFunctions) Create(ctx context.Context, acceleratorFunction *v1.AcceleratorFunction, opts metav1.CreateOptions) (result *v1.AcceleratorFunction, err error) {
result = &v1.AcceleratorFunction{}
func (c *acceleratorFunctions) Create(ctx context.Context, acceleratorFunction *v2.AcceleratorFunction, opts v1.CreateOptions) (result *v2.AcceleratorFunction, err error) {
result = &v2.AcceleratorFunction{}
err = c.client.Post().
Namespace(c.ns).
Resource("acceleratorfunctions").
@ -120,8 +120,8 @@ func (c *acceleratorFunctions) Create(ctx context.Context, acceleratorFunction *
}
// Update takes the representation of a acceleratorFunction and updates it. Returns the server's representation of the acceleratorFunction, and an error, if there is any.
func (c *acceleratorFunctions) Update(ctx context.Context, acceleratorFunction *v1.AcceleratorFunction, opts metav1.UpdateOptions) (result *v1.AcceleratorFunction, err error) {
result = &v1.AcceleratorFunction{}
func (c *acceleratorFunctions) Update(ctx context.Context, acceleratorFunction *v2.AcceleratorFunction, opts v1.UpdateOptions) (result *v2.AcceleratorFunction, err error) {
result = &v2.AcceleratorFunction{}
err = c.client.Put().
Namespace(c.ns).
Resource("acceleratorfunctions").
@ -134,7 +134,7 @@ func (c *acceleratorFunctions) Update(ctx context.Context, acceleratorFunction *
}
// Delete takes name of the acceleratorFunction and deletes it. Returns an error if one occurs.
func (c *acceleratorFunctions) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
func (c *acceleratorFunctions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("acceleratorfunctions").
@ -145,7 +145,7 @@ func (c *acceleratorFunctions) Delete(ctx context.Context, name string, opts met
}
// DeleteCollection deletes a collection of objects.
func (c *acceleratorFunctions) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
func (c *acceleratorFunctions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
@ -161,8 +161,8 @@ func (c *acceleratorFunctions) DeleteCollection(ctx context.Context, opts metav1
}
// Patch applies the patch and returns the patched acceleratorFunction.
func (c *acceleratorFunctions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.AcceleratorFunction, err error) {
result = &v1.AcceleratorFunction{}
func (c *acceleratorFunctions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.AcceleratorFunction, err error) {
result = &v2.AcceleratorFunction{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("acceleratorfunctions").

View File

@ -15,4 +15,4 @@
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1
package v2

View File

@ -19,7 +19,7 @@ package fake
import (
"context"
fpgaintelcomv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@ -30,29 +30,29 @@ import (
// FakeAcceleratorFunctions implements AcceleratorFunctionInterface
type FakeAcceleratorFunctions struct {
Fake *FakeFpgaV1
Fake *FakeFpgaV2
ns string
}
var acceleratorfunctionsResource = schema.GroupVersionResource{Group: "fpga.intel.com", Version: "v1", Resource: "acceleratorfunctions"}
var acceleratorfunctionsResource = schema.GroupVersionResource{Group: "fpga.intel.com", Version: "v2", Resource: "acceleratorfunctions"}
var acceleratorfunctionsKind = schema.GroupVersionKind{Group: "fpga.intel.com", Version: "v1", Kind: "AcceleratorFunction"}
var acceleratorfunctionsKind = schema.GroupVersionKind{Group: "fpga.intel.com", Version: "v2", Kind: "AcceleratorFunction"}
// Get takes name of the acceleratorFunction, and returns the corresponding acceleratorFunction object, and an error if there is any.
func (c *FakeAcceleratorFunctions) Get(ctx context.Context, name string, options v1.GetOptions) (result *fpgaintelcomv1.AcceleratorFunction, err error) {
func (c *FakeAcceleratorFunctions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2.AcceleratorFunction, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(acceleratorfunctionsResource, c.ns, name), &fpgaintelcomv1.AcceleratorFunction{})
Invokes(testing.NewGetAction(acceleratorfunctionsResource, c.ns, name), &v2.AcceleratorFunction{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.AcceleratorFunction), err
return obj.(*v2.AcceleratorFunction), err
}
// List takes label and field selectors, and returns the list of AcceleratorFunctions that match those selectors.
func (c *FakeAcceleratorFunctions) List(ctx context.Context, opts v1.ListOptions) (result *fpgaintelcomv1.AcceleratorFunctionList, err error) {
func (c *FakeAcceleratorFunctions) List(ctx context.Context, opts v1.ListOptions) (result *v2.AcceleratorFunctionList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(acceleratorfunctionsResource, acceleratorfunctionsKind, c.ns, opts), &fpgaintelcomv1.AcceleratorFunctionList{})
Invokes(testing.NewListAction(acceleratorfunctionsResource, acceleratorfunctionsKind, c.ns, opts), &v2.AcceleratorFunctionList{})
if obj == nil {
return nil, err
@ -62,8 +62,8 @@ func (c *FakeAcceleratorFunctions) List(ctx context.Context, opts v1.ListOptions
if label == nil {
label = labels.Everything()
}
list := &fpgaintelcomv1.AcceleratorFunctionList{ListMeta: obj.(*fpgaintelcomv1.AcceleratorFunctionList).ListMeta}
for _, item := range obj.(*fpgaintelcomv1.AcceleratorFunctionList).Items {
list := &v2.AcceleratorFunctionList{ListMeta: obj.(*v2.AcceleratorFunctionList).ListMeta}
for _, item := range obj.(*v2.AcceleratorFunctionList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
@ -79,31 +79,31 @@ func (c *FakeAcceleratorFunctions) Watch(ctx context.Context, opts v1.ListOption
}
// Create takes the representation of a acceleratorFunction and creates it. Returns the server's representation of the acceleratorFunction, and an error, if there is any.
func (c *FakeAcceleratorFunctions) Create(ctx context.Context, acceleratorFunction *fpgaintelcomv1.AcceleratorFunction, opts v1.CreateOptions) (result *fpgaintelcomv1.AcceleratorFunction, err error) {
func (c *FakeAcceleratorFunctions) Create(ctx context.Context, acceleratorFunction *v2.AcceleratorFunction, opts v1.CreateOptions) (result *v2.AcceleratorFunction, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(acceleratorfunctionsResource, c.ns, acceleratorFunction), &fpgaintelcomv1.AcceleratorFunction{})
Invokes(testing.NewCreateAction(acceleratorfunctionsResource, c.ns, acceleratorFunction), &v2.AcceleratorFunction{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.AcceleratorFunction), err
return obj.(*v2.AcceleratorFunction), err
}
// Update takes the representation of a acceleratorFunction and updates it. Returns the server's representation of the acceleratorFunction, and an error, if there is any.
func (c *FakeAcceleratorFunctions) Update(ctx context.Context, acceleratorFunction *fpgaintelcomv1.AcceleratorFunction, opts v1.UpdateOptions) (result *fpgaintelcomv1.AcceleratorFunction, err error) {
func (c *FakeAcceleratorFunctions) Update(ctx context.Context, acceleratorFunction *v2.AcceleratorFunction, opts v1.UpdateOptions) (result *v2.AcceleratorFunction, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(acceleratorfunctionsResource, c.ns, acceleratorFunction), &fpgaintelcomv1.AcceleratorFunction{})
Invokes(testing.NewUpdateAction(acceleratorfunctionsResource, c.ns, acceleratorFunction), &v2.AcceleratorFunction{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.AcceleratorFunction), err
return obj.(*v2.AcceleratorFunction), err
}
// Delete takes name of the acceleratorFunction and deletes it. Returns an error if one occurs.
func (c *FakeAcceleratorFunctions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(acceleratorfunctionsResource, c.ns, name), &fpgaintelcomv1.AcceleratorFunction{})
Invokes(testing.NewDeleteAction(acceleratorfunctionsResource, c.ns, name), &v2.AcceleratorFunction{})
return err
}
@ -112,17 +112,17 @@ func (c *FakeAcceleratorFunctions) Delete(ctx context.Context, name string, opts
func (c *FakeAcceleratorFunctions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(acceleratorfunctionsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &fpgaintelcomv1.AcceleratorFunctionList{})
_, err := c.Fake.Invokes(action, &v2.AcceleratorFunctionList{})
return err
}
// Patch applies the patch and returns the patched acceleratorFunction.
func (c *FakeAcceleratorFunctions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *fpgaintelcomv1.AcceleratorFunction, err error) {
func (c *FakeAcceleratorFunctions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.AcceleratorFunction, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(acceleratorfunctionsResource, c.ns, name, pt, data, subresources...), &fpgaintelcomv1.AcceleratorFunction{})
Invokes(testing.NewPatchSubresourceAction(acceleratorfunctionsResource, c.ns, name, pt, data, subresources...), &v2.AcceleratorFunction{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.AcceleratorFunction), err
return obj.(*v2.AcceleratorFunction), err
}

View File

@ -17,26 +17,26 @@
package fake
import (
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/typed/fpga.intel.com/v2"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeFpgaV1 struct {
type FakeFpgaV2 struct {
*testing.Fake
}
func (c *FakeFpgaV1) AcceleratorFunctions(namespace string) v1.AcceleratorFunctionInterface {
func (c *FakeFpgaV2) AcceleratorFunctions(namespace string) v2.AcceleratorFunctionInterface {
return &FakeAcceleratorFunctions{c, namespace}
}
func (c *FakeFpgaV1) FpgaRegions(namespace string) v1.FpgaRegionInterface {
func (c *FakeFpgaV2) FpgaRegions(namespace string) v2.FpgaRegionInterface {
return &FakeFpgaRegions{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeFpgaV1) RESTClient() rest.Interface {
func (c *FakeFpgaV2) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@ -19,7 +19,7 @@ package fake
import (
"context"
fpgaintelcomv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@ -30,29 +30,29 @@ import (
// FakeFpgaRegions implements FpgaRegionInterface
type FakeFpgaRegions struct {
Fake *FakeFpgaV1
Fake *FakeFpgaV2
ns string
}
var fpgaregionsResource = schema.GroupVersionResource{Group: "fpga.intel.com", Version: "v1", Resource: "fpgaregions"}
var fpgaregionsResource = schema.GroupVersionResource{Group: "fpga.intel.com", Version: "v2", Resource: "fpgaregions"}
var fpgaregionsKind = schema.GroupVersionKind{Group: "fpga.intel.com", Version: "v1", Kind: "FpgaRegion"}
var fpgaregionsKind = schema.GroupVersionKind{Group: "fpga.intel.com", Version: "v2", Kind: "FpgaRegion"}
// Get takes name of the fpgaRegion, and returns the corresponding fpgaRegion object, and an error if there is any.
func (c *FakeFpgaRegions) Get(ctx context.Context, name string, options v1.GetOptions) (result *fpgaintelcomv1.FpgaRegion, err error) {
func (c *FakeFpgaRegions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2.FpgaRegion, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(fpgaregionsResource, c.ns, name), &fpgaintelcomv1.FpgaRegion{})
Invokes(testing.NewGetAction(fpgaregionsResource, c.ns, name), &v2.FpgaRegion{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.FpgaRegion), err
return obj.(*v2.FpgaRegion), err
}
// List takes label and field selectors, and returns the list of FpgaRegions that match those selectors.
func (c *FakeFpgaRegions) List(ctx context.Context, opts v1.ListOptions) (result *fpgaintelcomv1.FpgaRegionList, err error) {
func (c *FakeFpgaRegions) List(ctx context.Context, opts v1.ListOptions) (result *v2.FpgaRegionList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(fpgaregionsResource, fpgaregionsKind, c.ns, opts), &fpgaintelcomv1.FpgaRegionList{})
Invokes(testing.NewListAction(fpgaregionsResource, fpgaregionsKind, c.ns, opts), &v2.FpgaRegionList{})
if obj == nil {
return nil, err
@ -62,8 +62,8 @@ func (c *FakeFpgaRegions) List(ctx context.Context, opts v1.ListOptions) (result
if label == nil {
label = labels.Everything()
}
list := &fpgaintelcomv1.FpgaRegionList{ListMeta: obj.(*fpgaintelcomv1.FpgaRegionList).ListMeta}
for _, item := range obj.(*fpgaintelcomv1.FpgaRegionList).Items {
list := &v2.FpgaRegionList{ListMeta: obj.(*v2.FpgaRegionList).ListMeta}
for _, item := range obj.(*v2.FpgaRegionList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
@ -79,31 +79,31 @@ func (c *FakeFpgaRegions) Watch(ctx context.Context, opts v1.ListOptions) (watch
}
// Create takes the representation of a fpgaRegion and creates it. Returns the server's representation of the fpgaRegion, and an error, if there is any.
func (c *FakeFpgaRegions) Create(ctx context.Context, fpgaRegion *fpgaintelcomv1.FpgaRegion, opts v1.CreateOptions) (result *fpgaintelcomv1.FpgaRegion, err error) {
func (c *FakeFpgaRegions) Create(ctx context.Context, fpgaRegion *v2.FpgaRegion, opts v1.CreateOptions) (result *v2.FpgaRegion, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(fpgaregionsResource, c.ns, fpgaRegion), &fpgaintelcomv1.FpgaRegion{})
Invokes(testing.NewCreateAction(fpgaregionsResource, c.ns, fpgaRegion), &v2.FpgaRegion{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.FpgaRegion), err
return obj.(*v2.FpgaRegion), err
}
// Update takes the representation of a fpgaRegion and updates it. Returns the server's representation of the fpgaRegion, and an error, if there is any.
func (c *FakeFpgaRegions) Update(ctx context.Context, fpgaRegion *fpgaintelcomv1.FpgaRegion, opts v1.UpdateOptions) (result *fpgaintelcomv1.FpgaRegion, err error) {
func (c *FakeFpgaRegions) Update(ctx context.Context, fpgaRegion *v2.FpgaRegion, opts v1.UpdateOptions) (result *v2.FpgaRegion, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(fpgaregionsResource, c.ns, fpgaRegion), &fpgaintelcomv1.FpgaRegion{})
Invokes(testing.NewUpdateAction(fpgaregionsResource, c.ns, fpgaRegion), &v2.FpgaRegion{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.FpgaRegion), err
return obj.(*v2.FpgaRegion), err
}
// Delete takes name of the fpgaRegion and deletes it. Returns an error if one occurs.
func (c *FakeFpgaRegions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(fpgaregionsResource, c.ns, name), &fpgaintelcomv1.FpgaRegion{})
Invokes(testing.NewDeleteAction(fpgaregionsResource, c.ns, name), &v2.FpgaRegion{})
return err
}
@ -112,17 +112,17 @@ func (c *FakeFpgaRegions) Delete(ctx context.Context, name string, opts v1.Delet
func (c *FakeFpgaRegions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(fpgaregionsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &fpgaintelcomv1.FpgaRegionList{})
_, err := c.Fake.Invokes(action, &v2.FpgaRegionList{})
return err
}
// Patch applies the patch and returns the patched fpgaRegion.
func (c *FakeFpgaRegions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *fpgaintelcomv1.FpgaRegion, err error) {
func (c *FakeFpgaRegions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.FpgaRegion, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(fpgaregionsResource, c.ns, name, pt, data, subresources...), &fpgaintelcomv1.FpgaRegion{})
Invokes(testing.NewPatchSubresourceAction(fpgaregionsResource, c.ns, name, pt, data, subresources...), &v2.FpgaRegion{})
if obj == nil {
return nil, err
}
return obj.(*fpgaintelcomv1.FpgaRegion), err
return obj.(*v2.FpgaRegion), err
}

View File

@ -14,35 +14,35 @@
// Code generated by client-gen. DO NOT EDIT.
package v1
package v2
import (
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
"github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type FpgaV1Interface interface {
type FpgaV2Interface interface {
RESTClient() rest.Interface
AcceleratorFunctionsGetter
FpgaRegionsGetter
}
// FpgaV1Client is used to interact with features provided by the fpga.intel.com group.
type FpgaV1Client struct {
// FpgaV2Client is used to interact with features provided by the fpga.intel.com group.
type FpgaV2Client struct {
restClient rest.Interface
}
func (c *FpgaV1Client) AcceleratorFunctions(namespace string) AcceleratorFunctionInterface {
func (c *FpgaV2Client) AcceleratorFunctions(namespace string) AcceleratorFunctionInterface {
return newAcceleratorFunctions(c, namespace)
}
func (c *FpgaV1Client) FpgaRegions(namespace string) FpgaRegionInterface {
func (c *FpgaV2Client) FpgaRegions(namespace string) FpgaRegionInterface {
return newFpgaRegions(c, namespace)
}
// NewForConfig creates a new FpgaV1Client for the given config.
func NewForConfig(c *rest.Config) (*FpgaV1Client, error) {
// NewForConfig creates a new FpgaV2Client for the given config.
func NewForConfig(c *rest.Config) (*FpgaV2Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
@ -51,12 +51,12 @@ func NewForConfig(c *rest.Config) (*FpgaV1Client, error) {
if err != nil {
return nil, err
}
return &FpgaV1Client{client}, nil
return &FpgaV2Client{client}, nil
}
// NewForConfigOrDie creates a new FpgaV1Client for the given config and
// NewForConfigOrDie creates a new FpgaV2Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *FpgaV1Client {
func NewForConfigOrDie(c *rest.Config) *FpgaV2Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
@ -64,13 +64,13 @@ func NewForConfigOrDie(c *rest.Config) *FpgaV1Client {
return client
}
// New creates a new FpgaV1Client for the given RESTClient.
func New(c rest.Interface) *FpgaV1Client {
return &FpgaV1Client{c}
// New creates a new FpgaV2Client for the given RESTClient.
func New(c rest.Interface) *FpgaV2Client {
return &FpgaV2Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1.SchemeGroupVersion
gv := v2.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
@ -84,7 +84,7 @@ func setConfigDefaults(config *rest.Config) error {
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FpgaV1Client) RESTClient() rest.Interface {
func (c *FpgaV2Client) RESTClient() rest.Interface {
if c == nil {
return nil
}

View File

@ -14,15 +14,15 @@
// Code generated by client-gen. DO NOT EDIT.
package v1
package v2
import (
"context"
"time"
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
scheme "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned/scheme"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
@ -36,14 +36,14 @@ type FpgaRegionsGetter interface {
// FpgaRegionInterface has methods to work with FpgaRegion resources.
type FpgaRegionInterface interface {
Create(ctx context.Context, fpgaRegion *v1.FpgaRegion, opts metav1.CreateOptions) (*v1.FpgaRegion, error)
Update(ctx context.Context, fpgaRegion *v1.FpgaRegion, opts metav1.UpdateOptions) (*v1.FpgaRegion, error)
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.FpgaRegion, error)
List(ctx context.Context, opts metav1.ListOptions) (*v1.FpgaRegionList, error)
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.FpgaRegion, err error)
Create(ctx context.Context, fpgaRegion *v2.FpgaRegion, opts v1.CreateOptions) (*v2.FpgaRegion, error)
Update(ctx context.Context, fpgaRegion *v2.FpgaRegion, opts v1.UpdateOptions) (*v2.FpgaRegion, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v2.FpgaRegion, error)
List(ctx context.Context, opts v1.ListOptions) (*v2.FpgaRegionList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.FpgaRegion, err error)
FpgaRegionExpansion
}
@ -54,7 +54,7 @@ type fpgaRegions struct {
}
// newFpgaRegions returns a FpgaRegions
func newFpgaRegions(c *FpgaV1Client, namespace string) *fpgaRegions {
func newFpgaRegions(c *FpgaV2Client, namespace string) *fpgaRegions {
return &fpgaRegions{
client: c.RESTClient(),
ns: namespace,
@ -62,8 +62,8 @@ func newFpgaRegions(c *FpgaV1Client, namespace string) *fpgaRegions {
}
// Get takes name of the fpgaRegion, and returns the corresponding fpgaRegion object, and an error if there is any.
func (c *fpgaRegions) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.FpgaRegion, err error) {
result = &v1.FpgaRegion{}
func (c *fpgaRegions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2.FpgaRegion, err error) {
result = &v2.FpgaRegion{}
err = c.client.Get().
Namespace(c.ns).
Resource("fpgaregions").
@ -75,12 +75,12 @@ func (c *fpgaRegions) Get(ctx context.Context, name string, options metav1.GetOp
}
// List takes label and field selectors, and returns the list of FpgaRegions that match those selectors.
func (c *fpgaRegions) List(ctx context.Context, opts metav1.ListOptions) (result *v1.FpgaRegionList, err error) {
func (c *fpgaRegions) List(ctx context.Context, opts v1.ListOptions) (result *v2.FpgaRegionList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1.FpgaRegionList{}
result = &v2.FpgaRegionList{}
err = c.client.Get().
Namespace(c.ns).
Resource("fpgaregions").
@ -92,7 +92,7 @@ func (c *fpgaRegions) List(ctx context.Context, opts metav1.ListOptions) (result
}
// Watch returns a watch.Interface that watches the requested fpgaRegions.
func (c *fpgaRegions) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
func (c *fpgaRegions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
@ -107,8 +107,8 @@ func (c *fpgaRegions) Watch(ctx context.Context, opts metav1.ListOptions) (watch
}
// Create takes the representation of a fpgaRegion and creates it. Returns the server's representation of the fpgaRegion, and an error, if there is any.
func (c *fpgaRegions) Create(ctx context.Context, fpgaRegion *v1.FpgaRegion, opts metav1.CreateOptions) (result *v1.FpgaRegion, err error) {
result = &v1.FpgaRegion{}
func (c *fpgaRegions) Create(ctx context.Context, fpgaRegion *v2.FpgaRegion, opts v1.CreateOptions) (result *v2.FpgaRegion, err error) {
result = &v2.FpgaRegion{}
err = c.client.Post().
Namespace(c.ns).
Resource("fpgaregions").
@ -120,8 +120,8 @@ func (c *fpgaRegions) Create(ctx context.Context, fpgaRegion *v1.FpgaRegion, opt
}
// Update takes the representation of a fpgaRegion and updates it. Returns the server's representation of the fpgaRegion, and an error, if there is any.
func (c *fpgaRegions) Update(ctx context.Context, fpgaRegion *v1.FpgaRegion, opts metav1.UpdateOptions) (result *v1.FpgaRegion, err error) {
result = &v1.FpgaRegion{}
func (c *fpgaRegions) Update(ctx context.Context, fpgaRegion *v2.FpgaRegion, opts v1.UpdateOptions) (result *v2.FpgaRegion, err error) {
result = &v2.FpgaRegion{}
err = c.client.Put().
Namespace(c.ns).
Resource("fpgaregions").
@ -134,7 +134,7 @@ func (c *fpgaRegions) Update(ctx context.Context, fpgaRegion *v1.FpgaRegion, opt
}
// Delete takes name of the fpgaRegion and deletes it. Returns an error if one occurs.
func (c *fpgaRegions) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
func (c *fpgaRegions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("fpgaregions").
@ -145,7 +145,7 @@ func (c *fpgaRegions) Delete(ctx context.Context, name string, opts metav1.Delet
}
// DeleteCollection deletes a collection of objects.
func (c *fpgaRegions) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
func (c *fpgaRegions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
@ -161,8 +161,8 @@ func (c *fpgaRegions) DeleteCollection(ctx context.Context, opts metav1.DeleteOp
}
// Patch applies the patch and returns the patched fpgaRegion.
func (c *fpgaRegions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.FpgaRegion, err error) {
result = &v1.FpgaRegion{}
func (c *fpgaRegions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.FpgaRegion, err error) {
result = &v2.FpgaRegion{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("fpgaregions").

View File

@ -14,7 +14,7 @@
// Code generated by client-gen. DO NOT EDIT.
package v1
package v2
type AcceleratorFunctionExpansion interface{}

View File

@ -17,14 +17,14 @@
package fpga
import (
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions/fpga.intel.com/v2"
internalinterfaces "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.Interface
// V2 provides access to shared informers for resources in V2.
V2() v2.Interface
}
type group struct {
@ -38,7 +38,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1 returns a new v1.Interface.
func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
// V2 returns a new v2.Interface.
func (g *group) V2() v2.Interface {
return v2.New(g.factory, g.namespace, g.tweakListOptions)
}

View File

@ -14,17 +14,17 @@
// Code generated by informer-gen. DO NOT EDIT.
package v1
package v2
import (
"context"
time "time"
fpgaintelcomv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
fpgaintelcomv2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
versioned "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned"
internalinterfaces "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions/internalinterfaces"
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
@ -34,7 +34,7 @@ import (
// AcceleratorFunctions.
type AcceleratorFunctionInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.AcceleratorFunctionLister
Lister() v2.AcceleratorFunctionLister
}
type acceleratorFunctionInformer struct {
@ -56,20 +56,20 @@ func NewAcceleratorFunctionInformer(client versioned.Interface, namespace string
func NewFilteredAcceleratorFunctionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FpgaV1().AcceleratorFunctions(namespace).List(context.TODO(), options)
return client.FpgaV2().AcceleratorFunctions(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FpgaV1().AcceleratorFunctions(namespace).Watch(context.TODO(), options)
return client.FpgaV2().AcceleratorFunctions(namespace).Watch(context.TODO(), options)
},
},
&fpgaintelcomv1.AcceleratorFunction{},
&fpgaintelcomv2.AcceleratorFunction{},
resyncPeriod,
indexers,
)
@ -80,9 +80,9 @@ func (f *acceleratorFunctionInformer) defaultInformer(client versioned.Interface
}
func (f *acceleratorFunctionInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&fpgaintelcomv1.AcceleratorFunction{}, f.defaultInformer)
return f.factory.InformerFor(&fpgaintelcomv2.AcceleratorFunction{}, f.defaultInformer)
}
func (f *acceleratorFunctionInformer) Lister() v1.AcceleratorFunctionLister {
return v1.NewAcceleratorFunctionLister(f.Informer().GetIndexer())
func (f *acceleratorFunctionInformer) Lister() v2.AcceleratorFunctionLister {
return v2.NewAcceleratorFunctionLister(f.Informer().GetIndexer())
}

View File

@ -14,17 +14,17 @@
// Code generated by informer-gen. DO NOT EDIT.
package v1
package v2
import (
"context"
time "time"
fpgaintelcomv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
fpgaintelcomv2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
versioned "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/clientset/versioned"
internalinterfaces "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions/internalinterfaces"
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/listers/fpga.intel.com/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
@ -34,7 +34,7 @@ import (
// FpgaRegions.
type FpgaRegionInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.FpgaRegionLister
Lister() v2.FpgaRegionLister
}
type fpgaRegionInformer struct {
@ -56,20 +56,20 @@ func NewFpgaRegionInformer(client versioned.Interface, namespace string, resyncP
func NewFilteredFpgaRegionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FpgaV1().FpgaRegions(namespace).List(context.TODO(), options)
return client.FpgaV2().FpgaRegions(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FpgaV1().FpgaRegions(namespace).Watch(context.TODO(), options)
return client.FpgaV2().FpgaRegions(namespace).Watch(context.TODO(), options)
},
},
&fpgaintelcomv1.FpgaRegion{},
&fpgaintelcomv2.FpgaRegion{},
resyncPeriod,
indexers,
)
@ -80,9 +80,9 @@ func (f *fpgaRegionInformer) defaultInformer(client versioned.Interface, resyncP
}
func (f *fpgaRegionInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&fpgaintelcomv1.FpgaRegion{}, f.defaultInformer)
return f.factory.InformerFor(&fpgaintelcomv2.FpgaRegion{}, f.defaultInformer)
}
func (f *fpgaRegionInformer) Lister() v1.FpgaRegionLister {
return v1.NewFpgaRegionLister(f.Informer().GetIndexer())
func (f *fpgaRegionInformer) Lister() v2.FpgaRegionLister {
return v2.NewFpgaRegionLister(f.Informer().GetIndexer())
}

View File

@ -14,7 +14,7 @@
// Code generated by informer-gen. DO NOT EDIT.
package v1
package v2
import (
internalinterfaces "github.com/intel/intel-device-plugins-for-kubernetes/pkg/client/informers/externalversions/internalinterfaces"

View File

@ -19,7 +19,7 @@ package externalversions
import (
"fmt"
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
)
@ -50,11 +50,11 @@ func (f *genericInformer) Lister() cache.GenericLister {
// TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource {
// Group=fpga.intel.com, Version=v1
case v1.SchemeGroupVersion.WithResource("acceleratorfunctions"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Fpga().V1().AcceleratorFunctions().Informer()}, nil
case v1.SchemeGroupVersion.WithResource("fpgaregions"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Fpga().V1().FpgaRegions().Informer()}, nil
// Group=fpga.intel.com, Version=v2
case v2.SchemeGroupVersion.WithResource("acceleratorfunctions"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Fpga().V2().AcceleratorFunctions().Informer()}, nil
case v2.SchemeGroupVersion.WithResource("fpgaregions"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Fpga().V2().FpgaRegions().Informer()}, nil
}

View File

@ -14,10 +14,10 @@
// Code generated by lister-gen. DO NOT EDIT.
package v1
package v2
import (
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
@ -26,7 +26,7 @@ import (
// AcceleratorFunctionLister helps list AcceleratorFunctions.
type AcceleratorFunctionLister interface {
// List lists all AcceleratorFunctions in the indexer.
List(selector labels.Selector) (ret []*v1.AcceleratorFunction, err error)
List(selector labels.Selector) (ret []*v2.AcceleratorFunction, err error)
// AcceleratorFunctions returns an object that can list and get AcceleratorFunctions.
AcceleratorFunctions(namespace string) AcceleratorFunctionNamespaceLister
AcceleratorFunctionListerExpansion
@ -43,9 +43,9 @@ func NewAcceleratorFunctionLister(indexer cache.Indexer) AcceleratorFunctionList
}
// List lists all AcceleratorFunctions in the indexer.
func (s *acceleratorFunctionLister) List(selector labels.Selector) (ret []*v1.AcceleratorFunction, err error) {
func (s *acceleratorFunctionLister) List(selector labels.Selector) (ret []*v2.AcceleratorFunction, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.AcceleratorFunction))
ret = append(ret, m.(*v2.AcceleratorFunction))
})
return ret, err
}
@ -58,9 +58,9 @@ func (s *acceleratorFunctionLister) AcceleratorFunctions(namespace string) Accel
// AcceleratorFunctionNamespaceLister helps list and get AcceleratorFunctions.
type AcceleratorFunctionNamespaceLister interface {
// List lists all AcceleratorFunctions in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1.AcceleratorFunction, err error)
List(selector labels.Selector) (ret []*v2.AcceleratorFunction, err error)
// Get retrieves the AcceleratorFunction from the indexer for a given namespace and name.
Get(name string) (*v1.AcceleratorFunction, error)
Get(name string) (*v2.AcceleratorFunction, error)
AcceleratorFunctionNamespaceListerExpansion
}
@ -72,21 +72,21 @@ type acceleratorFunctionNamespaceLister struct {
}
// List lists all AcceleratorFunctions in the indexer for a given namespace.
func (s acceleratorFunctionNamespaceLister) List(selector labels.Selector) (ret []*v1.AcceleratorFunction, err error) {
func (s acceleratorFunctionNamespaceLister) List(selector labels.Selector) (ret []*v2.AcceleratorFunction, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.AcceleratorFunction))
ret = append(ret, m.(*v2.AcceleratorFunction))
})
return ret, err
}
// Get retrieves the AcceleratorFunction from the indexer for a given namespace and name.
func (s acceleratorFunctionNamespaceLister) Get(name string) (*v1.AcceleratorFunction, error) {
func (s acceleratorFunctionNamespaceLister) Get(name string) (*v2.AcceleratorFunction, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1.Resource("acceleratorfunction"), name)
return nil, errors.NewNotFound(v2.Resource("acceleratorfunction"), name)
}
return obj.(*v1.AcceleratorFunction), nil
return obj.(*v2.AcceleratorFunction), nil
}

View File

@ -14,7 +14,7 @@
// Code generated by lister-gen. DO NOT EDIT.
package v1
package v2
// AcceleratorFunctionListerExpansion allows custom methods to be added to
// AcceleratorFunctionLister.

View File

@ -14,10 +14,10 @@
// Code generated by lister-gen. DO NOT EDIT.
package v1
package v2
import (
v1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v1"
v2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga.intel.com/v2"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
@ -26,7 +26,7 @@ import (
// FpgaRegionLister helps list FpgaRegions.
type FpgaRegionLister interface {
// List lists all FpgaRegions in the indexer.
List(selector labels.Selector) (ret []*v1.FpgaRegion, err error)
List(selector labels.Selector) (ret []*v2.FpgaRegion, err error)
// FpgaRegions returns an object that can list and get FpgaRegions.
FpgaRegions(namespace string) FpgaRegionNamespaceLister
FpgaRegionListerExpansion
@ -43,9 +43,9 @@ func NewFpgaRegionLister(indexer cache.Indexer) FpgaRegionLister {
}
// List lists all FpgaRegions in the indexer.
func (s *fpgaRegionLister) List(selector labels.Selector) (ret []*v1.FpgaRegion, err error) {
func (s *fpgaRegionLister) List(selector labels.Selector) (ret []*v2.FpgaRegion, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.FpgaRegion))
ret = append(ret, m.(*v2.FpgaRegion))
})
return ret, err
}
@ -58,9 +58,9 @@ func (s *fpgaRegionLister) FpgaRegions(namespace string) FpgaRegionNamespaceList
// FpgaRegionNamespaceLister helps list and get FpgaRegions.
type FpgaRegionNamespaceLister interface {
// List lists all FpgaRegions in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1.FpgaRegion, err error)
List(selector labels.Selector) (ret []*v2.FpgaRegion, err error)
// Get retrieves the FpgaRegion from the indexer for a given namespace and name.
Get(name string) (*v1.FpgaRegion, error)
Get(name string) (*v2.FpgaRegion, error)
FpgaRegionNamespaceListerExpansion
}
@ -72,21 +72,21 @@ type fpgaRegionNamespaceLister struct {
}
// List lists all FpgaRegions in the indexer for a given namespace.
func (s fpgaRegionNamespaceLister) List(selector labels.Selector) (ret []*v1.FpgaRegion, err error) {
func (s fpgaRegionNamespaceLister) List(selector labels.Selector) (ret []*v2.FpgaRegion, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.FpgaRegion))
ret = append(ret, m.(*v2.FpgaRegion))
})
return ret, err
}
// Get retrieves the FpgaRegion from the indexer for a given namespace and name.
func (s fpgaRegionNamespaceLister) Get(name string) (*v1.FpgaRegion, error) {
func (s fpgaRegionNamespaceLister) Get(name string) (*v2.FpgaRegion, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1.Resource("fpgaregion"), name)
return nil, errors.NewNotFound(v2.Resource("fpgaregion"), name)
}
return obj.(*v1.FpgaRegion), nil
return obj.(*v2.FpgaRegion), nil
}

36
pkg/fpga/devtypes.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2020 Intel Corporation. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fpga
import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/pkg/errors"
)
// GetAfuDevType returns extended resource name for AFU without namespace.
// Since in Linux unix socket addresses can't be longer than 108 chars we need
// to compress devtype a bit, because it's used as a part of the socket's address.
// Also names of extended resources (without namespace) cannot be longer than 63 characters.
func GetAfuDevType(interfaceID, afuID string) (string, error) {
bin, err := hex.DecodeString(interfaceID + afuID)
if err != nil {
return "", errors.Wrapf(err, "failed to decode %q and %q", interfaceID, afuID)
}
return fmt.Sprintf("af-%s.%s.%s", interfaceID[:3], afuID[:3], base64.RawURLEncoding.EncodeToString(bin)), nil
}

66
pkg/fpga/devtypes_test.go Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2020 Intel Corporation. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fpga
import (
"flag"
"testing"
)
func init() {
flag.Set("v", "4")
}
func TestGetAfuDevType(t *testing.T) {
tcases := []struct {
name string
interfaceID string
afuID string
expectedDevType string
expectedErr bool
}{
{
name: "Everything is correct 1",
interfaceID: "ce48969398f05f33946d560708be108a",
afuID: "d8424dc4a4a3c413f89e433683f9040b",
expectedDevType: "af-ce4.d84.zkiWk5jwXzOUbVYHCL4QithCTcSko8QT-J5DNoP5BAs",
},
{
name: "Everything is correct 2",
interfaceID: "bfac4d851ee856fe8c95865ce1bbaa2d",
afuID: "f7df405cbd7acf7222f144b0b93acd18",
expectedDevType: "af-bfa.f7d.v6xNhR7oVv6MlYZc4buqLfffQFy9es9yIvFEsLk6zRg",
},
{
name: "unparsable interfaceID",
interfaceID: "unparsable",
expectedErr: true,
},
}
for _, tt := range tcases {
t.Run(tt.name, func(t *testing.T) {
devtype, err := GetAfuDevType(tt.interfaceID, tt.afuID)
if tt.expectedErr && err == nil {
t.Errorf("no error returned")
}
if !tt.expectedErr && err != nil {
t.Errorf("unexpected error: %+v", err)
}
if tt.expectedDevType != devtype {
t.Errorf("expected %q, but got %q", tt.expectedDevType, devtype)
}
})
}
}

View File

@ -28,6 +28,6 @@ PKG_PATH="github.com/intel/intel-device-plugins-for-kubernetes/pkg"
# instead of the $GOPATH directly. For normal projects this can be dropped.
${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \
${PKG_PATH}/client ${PKG_PATH}/apis \
fpga.intel.com:v1 \
fpga.intel.com:v2 \
--output-base "$(dirname ${BASH_SOURCE})/../../../.." \
--go-header-file ${SCRIPT_ROOT}/build/boilerplate/boilerplate.go.txt

View File

@ -15,7 +15,6 @@ function help {
echo ''
echo ' Options:'
echo ' --kubectl <kubectl> - path to the kubectl utility'
echo ' --mode <mode> - "preprogrammed" (default) or "orchestrated" mode of operation'
echo ' --ca-bundle-path <path> - path to CA bundle used for signing cerificates in the cluster'
echo ' --namespace <name> - namespace to deploy the webhook in'
}
@ -30,10 +29,6 @@ while [[ $# -gt 0 ]]; do
cabundlepath="$2"
shift
;;
--mode)
mode="$2"
shift
;;
--namespace)
namespace="$2"
shift
@ -54,7 +49,6 @@ while [[ $# -gt 0 ]]; do
done
[ -z ${kubectl} ] && kubectl="kubectl"
[ -z ${mode} ] && mode="preprogrammed"
[ -z ${namespace} ] && namespace="default"
which ${kubectl} > /dev/null 2>&1 || { echo "ERROR: ${kubectl} not found"; exit 1; }
@ -75,11 +69,6 @@ if [ "x${command}" = "xcleanup" ]; then
exit 0
fi
if [ "x${mode}" != "xpreprogrammed" -a "x${mode}" != "xorchestrated" ]; then
echo "ERROR: supported modes are 'preprogrammed' and 'orchestrated'"
exit 1
fi
if [ -z ${cabundlepath} ]; then
CA_BUNDLE=$(${kubectl} get configmap -n kube-system extension-apiserver-authentication -o=jsonpath='{.data.client-ca-file}' | base64 -w 0)
else
@ -98,7 +87,7 @@ cat ${srcroot}/deployments/fpga_admissionwebhook/rbac-config-tpl.yaml | \
${kubectl} create -f -
echo "Create webhook deployment"
cat ${srcroot}/deployments/fpga_admissionwebhook/deployment-tpl.yaml | sed -e "s/{MODE}/${mode}/g" -e "s/{uid}/${uid}/g" -e "s/{gid}/${gid}/g" | ${kubectl} --namespace ${namespace} create -f -
cat ${srcroot}/deployments/fpga_admissionwebhook/deployment-tpl.yaml | sed -e "s/{uid}/${uid}/g" -e "s/{gid}/${gid}/g" | ${kubectl} --namespace ${namespace} create -f -
echo "Create webhook service"
${kubectl} --namespace ${namespace} create -f ${srcroot}/deployments/fpga_admissionwebhook/service.yaml

View File

@ -33,9 +33,10 @@ import (
const (
pluginDeployScript = "scripts/deploy-fpgaplugin.sh"
webhookDeployScript = "scripts/webhook-deploy.sh"
nlb0NodeResource = "fpga.intel.com/af-d8424dc4a4a3c413f89e433683f9040b"
nlb0PodResource = "fpga.intel.com/arria10.dcp1.2-nlb0"
nlb3PodResource = "fpga.intel.com/arria10.dcp1.2-nlb3"
nlb0NodeResource = "fpga.intel.com/af-695.d84.aVKNtusxV3qMNmj5-qCB9thCTcSko8QT-J5DNoP5BAs"
nlb0PodResource = "fpga.intel.com/arria10.dcp1.2-nlb0-orchestrated"
nlb3PodResource = "fpga.intel.com/arria10.dcp1.2-nlb3-orchestrated"
nlb0PodResourceAF = "fpga.intel.com/arria10.dcp1.2-nlb0-preprogrammed"
arria10NodeResource = "fpga.intel.com/region-69528db6eb31577a8c3668f9faa081f6"
)
@ -57,23 +58,23 @@ func describe() {
fmw := framework.NewDefaultFramework("fpgaplugin-e2e")
ginkgo.It("Run FPGA plugin tests", func() {
// Deploy webhook
ginkgo.By(fmt.Sprintf("namespace %s: deploying webhook", fmw.Namespace.Name))
_, _, err := framework.RunCmd(webhookDeployScriptPath, "--namespace", fmw.Namespace.Name)
framework.ExpectNoError(err)
waitForPod(fmw, "intel-fpga-webhook")
// Run region test case twice to ensure that device is reprogrammed at least once
runTestCase(fmw, webhookDeployScriptPath, pluginDeployScriptPath, "region", "orchestrated", arria10NodeResource, nlb3PodResource, "nlb3", "nlb0")
runTestCase(fmw, webhookDeployScriptPath, pluginDeployScriptPath, "region", "orchestrated", arria10NodeResource, nlb0PodResource, "nlb0", "nlb3")
runTestCase(fmw, pluginDeployScriptPath, "region", arria10NodeResource, nlb3PodResource, "nlb3", "nlb0")
runTestCase(fmw, pluginDeployScriptPath, "region", arria10NodeResource, nlb0PodResource, "nlb0", "nlb3")
// Run af test case
runTestCase(fmw, webhookDeployScriptPath, pluginDeployScriptPath, "af", "preprogrammed", nlb0NodeResource, nlb0PodResource, "nlb0", "nlb3")
runTestCase(fmw, pluginDeployScriptPath, "af", nlb0NodeResource, nlb0PodResourceAF, "nlb0", "nlb3")
})
}
func runTestCase(fmw *framework.Framework, webhookDeployScriptPath, pluginDeployScriptPath, pluginMode, webhookMode, nodeResource, podResource, cmd1, cmd2 string) {
ginkgo.By(fmt.Sprintf("deploying webhook in %s mode", webhookMode))
_, _, err := framework.RunCmd(webhookDeployScriptPath, "--mode", webhookMode, "--namespace", fmw.Namespace.Name)
framework.ExpectNoError(err)
waitForPod(fmw, "intel-fpga-webhook")
ginkgo.By(fmt.Sprintf("deploying FPGA plugin in %s mode", pluginMode))
_, _, err = framework.RunCmd(pluginDeployScriptPath, "--mode", pluginMode, "--namespace", fmw.Namespace.Name)
func runTestCase(fmw *framework.Framework, pluginDeployScriptPath, pluginMode, nodeResource, podResource, cmd1, cmd2 string) {
ginkgo.By(fmt.Sprintf("namespace %s: deploying FPGA plugin in %s mode", fmw.Namespace.Name, pluginMode))
_, _, err := framework.RunCmd(pluginDeployScriptPath, "--mode", pluginMode, "--namespace", fmw.Namespace.Name)
framework.ExpectNoError(err)
waitForPod(fmw, "intel-fpga-plugin")
@ -88,18 +89,17 @@ func runTestCase(fmw *framework.Framework, webhookDeployScriptPath, pluginDeploy
image := "intel/opae-nlb-demo:devel"
ginkgo.By("submitting a pod requesting correct FPGA resources")
pod := createPod(fmw, fmt.Sprintf("fpgaplugin-nlb-%s-%s-%s-correct", pluginMode, cmd1, cmd2), resource, image, []string{cmd1})
pod := createPod(fmw, fmt.Sprintf("fpgaplugin-%s-%s-%s-correct", pluginMode, cmd1, cmd2), resource, image, []string{cmd1, "-S0"})
ginkgo.By("waiting the pod to finish successfully")
fmw.PodClient().WaitForSuccess(pod.ObjectMeta.Name, 60*time.Second)
// If WaitForSuccess fails, ginkgo doesn't show the logs of the failed container.
// Replacing WaitForSuccess with WaitForFinish + 'kubelet logs' would show the logs
// fmw.PodClient().WaitForFinish(pod.ObjectMeta.Name, 60*time.Second)
// framework.RunKubectlOrDie(fmw.Namespace.Name, "--namespace", fmw.Namespace.Name, "logs", pod.ObjectMeta.Name)
// return
//fmw.PodClient().WaitForFinish(pod.ObjectMeta.Name, 60*time.Second)
//framework.RunKubectlOrDie(fmw.Namespace.Name, "--namespace", fmw.Namespace.Name, "logs", pod.ObjectMeta.Name)
ginkgo.By("submitting a pod requesting incorrect FPGA resources")
pod = createPod(fmw, fmt.Sprintf("fpgaplugin-nlb-%s-%s-%s-incorrect", pluginMode, cmd1, cmd2), resource, image, []string{cmd2})
pod = createPod(fmw, fmt.Sprintf("fpgaplugin-%s-%s-%s-incorrect", pluginMode, cmd1, cmd2), resource, image, []string{cmd2, "-S0"})
ginkgo.By("waiting the pod failure")
utils.WaitForPodFailure(fmw, pod.ObjectMeta.Name, 60*time.Second)

View File

@ -51,25 +51,37 @@ func describe() {
return append(os.Environ(), "KUBECONFIG="+framework.TestContext.KubeConfig)
}
ginkgo.It("mutates created pods to reference resolved AFs in preprogrammed mode", func() {
ginkgo.By("deploying webhook in preprogrammed mode")
ginkgo.It("mutates created pods to reference resolved AFs", func() {
ginkgo.By("deploying webhook")
_, _, err := framework.RunCmdEnv(getEnv(), webhookDeployPath, "--kubectl", framework.TestContext.KubectlPath, "--namespace", f.Namespace.Name)
framework.ExpectNoError(err)
checkPodMutation(f, "fpga.intel.com/af-d8424dc4a4a3c413f89e433683f9040b")
checkPodMutation(f, "fpga.intel.com/d5005-nlb3-preprogrammed",
"fpga.intel.com/af-bfa.f7d.v6xNhR7oVv6MlYZc4buqLfffQFy9es9yIvFEsLk6zRg")
})
ginkgo.It("mutates created pods to reference resolved Regions in orchestrated mode", func() {
ginkgo.By("deploying webhook in orchestrated mode")
_, _, err := framework.RunCmdEnv(getEnv(), webhookDeployPath, "--kubectl", framework.TestContext.KubectlPath, "--namespace", f.Namespace.Name, "--mode", "orchestrated")
ginkgo.It("mutates created pods to reference resolved Regions", func() {
ginkgo.By("deploying webhook")
_, _, err := framework.RunCmdEnv(getEnv(), webhookDeployPath, "--kubectl", framework.TestContext.KubectlPath, "--namespace", f.Namespace.Name)
framework.ExpectNoError(err)
checkPodMutation(f, "fpga.intel.com/region-ce48969398f05f33946d560708be108a")
checkPodMutation(f, "fpga.intel.com/arria10.dcp1.0-nlb0-orchestrated",
"fpga.intel.com/region-ce48969398f05f33946d560708be108a")
})
ginkgo.It("mutates created pods to reference resolved Regions in regiondevel mode", func() {
ginkgo.By("deploying webhook")
_, _, err := framework.RunCmdEnv(getEnv(), webhookDeployPath, "--kubectl", framework.TestContext.KubectlPath, "--namespace", f.Namespace.Name)
framework.ExpectNoError(err)
checkPodMutation(f, "fpga.intel.com/arria10.dcp1.0",
"fpga.intel.com/region-ce48969398f05f33946d560708be108a")
})
}
func checkPodMutation(f *framework.Framework, expectedMutation v1.ResourceName) {
func checkPodMutation(f *framework.Framework, source, expectedMutation v1.ResourceName) {
ginkgo.By("waiting for webhook's availability")
if _, err := e2epod.WaitForPodsWithLabelRunningReady(f.ClientSet, f.Namespace.Name,
labels.Set{"app": "intel-fpga-webhook"}.AsSelector(), 1 /* one replica */, 10*time.Second); err != nil {
@ -80,8 +92,8 @@ func checkPodMutation(f *framework.Framework, expectedMutation v1.ResourceName)
ginkgo.By("submitting a pod for addmission")
podSpec := f.NewTestPod("webhook-tester",
v1.ResourceList{"fpga.intel.com/arria10.dcp1.0-nlb0": resource.MustParse("1")},
v1.ResourceList{"fpga.intel.com/arria10.dcp1.0-nlb0": resource.MustParse("1")})
v1.ResourceList{source: resource.MustParse("1")},
v1.ResourceList{source: resource.MustParse("1")})
pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(),
podSpec, metav1.CreateOptions{})
framework.ExpectNoError(err, "pod Create API error")