From 9a02a4a9885aa56013f8d9e684bd0cb3ff00887a Mon Sep 17 00:00:00 2001 From: akutz Date: Fri, 20 Sep 2024 13:53:21 -0500 Subject: [PATCH] api: Support querying PBM profile for IOFILTERS This patch supports querying a PBM profile for IOFILTERS. --- pbm/client.go | 36 ++++++++++- pbm/client_test.go | 81 ++++++++++++++++------- pbm/methods/internal_methods.go | 44 +++++++++++++ pbm/simulator/profiles.go | 111 +++++++++++++++++--------------- pbm/simulator/simulator.go | 70 +++++++++++++++++--- pbm/simulator/simulator_test.go | 20 +++--- pbm/types/internal_types.go | 95 +++++++++++++++++++++++++++ 7 files changed, 358 insertions(+), 99 deletions(-) create mode 100644 pbm/methods/internal_methods.go create mode 100644 pbm/types/internal_types.go diff --git a/pbm/client.go b/pbm/client.go index 3c7965ca8..d8d2131cf 100644 --- a/pbm/client.go +++ b/pbm/client.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2024 VMware, Inc. 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 +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, @@ -313,3 +313,35 @@ func (c *Client) QueryAssociatedProfiles(ctx context.Context, entities []types.P return res.Returnval, nil } + +func (c *Client) QueryIOFiltersFromProfileId( + ctx context.Context, profileID string) ([]types.PbmProfileToIofilterMap, error) { + + req := types.PbmQueryIOFiltersFromProfileId{ + This: c.ServiceContent.ProfileManager, + ProfileIds: []types.PbmProfileId{{UniqueId: profileID}}, + } + res, err := methods.PbmQueryIOFiltersFromProfileId(ctx, c, &req) + if err != nil { + return nil, err + } + return res.Returnval, nil +} + +func (c *Client) SupportsEncryption( + ctx context.Context, profileID string) (bool, error) { + + list, err := c.QueryIOFiltersFromProfileId(ctx, profileID) + if err != nil { + return false, err + } + for i := range list { + for j := range list[i].Iofilters { + f := list[i].Iofilters[j] + if f.FilterType == string(types.PbmIofilterInfoFilterTypeENCRYPTION) { + return true, nil + } + } + } + return false, nil +} diff --git a/pbm/client_test.go b/pbm/client_test.go index a3666e946..0500e0509 100644 --- a/pbm/client_test.go +++ b/pbm/client_test.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2024 VMware, Inc. 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 +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, @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package pbm +package pbm_test import ( "context" @@ -23,10 +23,17 @@ import ( "sort" "testing" + "github.com/stretchr/testify/assert" + "github.com/vmware/govmomi" + "github.com/vmware/govmomi/fault" + "github.com/vmware/govmomi/pbm" + pbmsim "github.com/vmware/govmomi/pbm/simulator" "github.com/vmware/govmomi/pbm/types" "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/simulator" "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/soap" vim "github.com/vmware/govmomi/vim25/types" @@ -52,7 +59,7 @@ func TestClient(t *testing.T) { t.Fatal(err) } - pc, err := NewClient(ctx, c.Client) + pc, err := pbm.NewClient(ctx, c.Client) if err != nil { t.Fatal(err) } @@ -164,27 +171,27 @@ func TestClient(t *testing.T) { // user spec for the profile. // VSAN profile with 2 capability instances - hostFailuresToTolerate = 2, stripeWidth = 1 - pbmCreateSpecForVSAN := CapabilityProfileCreateSpec{ + pbmCreateSpecForVSAN := pbm.CapabilityProfileCreateSpec{ Name: "Kubernetes-VSAN-TestPolicy", Description: "VSAN Test policy create", Category: string(types.PbmProfileCategoryEnumREQUIREMENT), - CapabilityList: []Capability{ - Capability{ + CapabilityList: []pbm.Capability{ + { ID: "hostFailuresToTolerate", Namespace: "VSAN", - PropertyList: []Property{ - Property{ + PropertyList: []pbm.Property{ + { ID: "hostFailuresToTolerate", Value: "2", DataType: "int", }, }, }, - Capability{ + { ID: "stripeWidth", Namespace: "VSAN", - PropertyList: []Property{ - Property{ + PropertyList: []pbm.Property{ + { ID: "stripeWidth", Value: "1", DataType: "int", @@ -195,7 +202,7 @@ func TestClient(t *testing.T) { } // Create PBM capability spec for the above defined user spec. - createSpecVSAN, err := CreateCapabilityProfileSpec(pbmCreateSpecForVSAN) + createSpecVSAN, err := pbm.CreateCapabilityProfileSpec(pbmCreateSpecForVSAN) if err != nil { t.Fatal(err) } @@ -229,37 +236,37 @@ func TestClient(t *testing.T) { // user spec for the profile. // VSAN profile with 2 capability instances - stripeWidth = 1 and an SIOC profile. - pbmCreateSpecVSANandSIOC := CapabilityProfileCreateSpec{ + pbmCreateSpecVSANandSIOC := pbm.CapabilityProfileCreateSpec{ Name: "Kubernetes-VSAN-SIOC-TestPolicy", Description: "VSAN-SIOC-Test policy create", Category: string(types.PbmProfileCategoryEnumREQUIREMENT), - CapabilityList: []Capability{ - Capability{ + CapabilityList: []pbm.Capability{ + { ID: "stripeWidth", Namespace: "VSAN", - PropertyList: []Property{ - Property{ + PropertyList: []pbm.Property{ + { ID: "stripeWidth", Value: "1", DataType: "int", }, }, }, - Capability{ + { ID: "spm@DATASTOREIOCONTROL", Namespace: "spm", - PropertyList: []Property{ - Property{ + PropertyList: []pbm.Property{ + { ID: "limit", Value: "200", DataType: "int", }, - Property{ + { ID: "reservation", Value: "1000", DataType: "int", }, - Property{ + { ID: "shares", Value: "2000", DataType: "int", @@ -270,7 +277,7 @@ func TestClient(t *testing.T) { } // Create PBM capability spec for the above defined user spec. - createSpecVSANandSIOC, err := CreateCapabilityProfileSpec(pbmCreateSpecVSANandSIOC) + createSpecVSANandSIOC, err := pbm.CreateCapabilityProfileSpec(pbmCreateSpecVSANandSIOC) if err != nil { t.Fatal(err) } @@ -313,3 +320,29 @@ func TestClient(t *testing.T) { } t.Logf("Profile: %+v successfully deleted", []types.PbmProfileId{*vsanProfileID, *vsansiocProfileID}) } + +func TestSupportsEncryption(t *testing.T) { + t.Run("valid profile id", func(t *testing.T) { + simulator.Test(func(ctx context.Context, c *vim25.Client) { + pbmc, err := pbm.NewClient(ctx, c) + assert.NoError(t, err) + assert.NotNil(t, pbmc) + + ok, err := pbmc.SupportsEncryption(ctx, pbmsim.DefaultEncryptionProfileID) + assert.NoError(t, err) + assert.True(t, ok) + }) + }) + t.Run("invalid profile id", func(t *testing.T) { + simulator.Test(func(ctx context.Context, c *vim25.Client) { + pbmc, err := pbm.NewClient(ctx, c) + assert.NoError(t, err) + assert.NotNil(t, pbmc) + + ok, err := pbmc.SupportsEncryption(ctx, "invalid") + assert.EqualError(t, err, "ServerFaultCode: Invalid profile ID") + assert.True(t, fault.Is(err, &vim.RuntimeFault{})) + assert.False(t, ok) + }) + }) +} diff --git a/pbm/methods/internal_methods.go b/pbm/methods/internal_methods.go new file mode 100644 index 000000000..11b6fc503 --- /dev/null +++ b/pbm/methods/internal_methods.go @@ -0,0 +1,44 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. 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 methods + +import ( + "context" + + "github.com/vmware/govmomi/pbm/types" + "github.com/vmware/govmomi/vim25/soap" +) + +type PbmQueryIOFiltersFromProfileIdBody struct { + Req *types.PbmQueryIOFiltersFromProfileId `xml:"urn:pbm PbmQueryIOFiltersFromProfileId,omitempty"` + Res *types.PbmQueryIOFiltersFromProfileIdResponse `xml:"urn:pbm PbmQueryIOFiltersFromProfileIdResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *PbmQueryIOFiltersFromProfileIdBody) Fault() *soap.Fault { return b.Fault_ } + +func PbmQueryIOFiltersFromProfileId(ctx context.Context, r soap.RoundTripper, req *types.PbmQueryIOFiltersFromProfileId) (*types.PbmQueryIOFiltersFromProfileIdResponse, error) { + var reqBody, resBody PbmQueryIOFiltersFromProfileIdBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} diff --git a/pbm/simulator/profiles.go b/pbm/simulator/profiles.go index 636090e4b..92f003b9f 100644 --- a/pbm/simulator/profiles.go +++ b/pbm/simulator/profiles.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2024 VMware, Inc. 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 +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, @@ -23,8 +23,61 @@ import ( vim "github.com/vmware/govmomi/vim25/types" ) -// profiles is a captured from vCenter 6.7's default set of PBM profiles. -var profiles = []types.BasePbmProfile{ +const DefaultEncryptionProfileID = "4d5f673c-536f-11e6-beb8-9e71128cae77" + +var defaultEncryptionProfile = &types.PbmCapabilityProfile{ + PbmProfile: types.PbmProfile{ + ProfileId: types.PbmProfileId{ + UniqueId: DefaultEncryptionProfileID, + }, + Name: "VM Encryption Policy", + Description: "Sample storage policy for VMware's VM and virtual disk encryption", + CreationTime: time.Now(), + CreatedBy: "Temporary user handle", + LastUpdatedTime: time.Now(), + LastUpdatedBy: "Temporary user handle", + }, + ProfileCategory: "REQUIREMENT", + ResourceType: types.PbmProfileResourceType{ + ResourceType: "STORAGE", + }, + Constraints: &types.PbmCapabilitySubProfileConstraints{ + PbmCapabilityConstraints: types.PbmCapabilityConstraints{}, + SubProfiles: []types.PbmCapabilitySubProfile{ + { + Name: "sp-1", + Capability: []types.PbmCapabilityInstance{ + { + Id: types.PbmCapabilityMetadataUniqueId{ + Namespace: "com.vmware.storageprofile.dataservice", + Id: "ad5a249d-cbc2-43af-9366-694d7664fa52", + }, + Constraint: []types.PbmCapabilityConstraintInstance{ + { + PropertyInstance: []types.PbmCapabilityPropertyInstance{ + { + Id: "ad5a249d-cbc2-43af-9366-694d7664fa52", + Operator: "", + Value: "ad5a249d-cbc2-43af-9366-694d7664fa52", + }, + }, + }, + }, + }, + }, + ForceProvision: vim.NewBool(false), + }, + }, + }, + GenerationId: 0, + IsDefault: false, + SystemCreatedProfileType: "", + LineOfService: "", +} + +// vcenter67DefaultProfiles is a captured from vCenter 6.7's default set of PBM +// profiles. +var vcenter67DefaultProfiles = []types.BasePbmProfile{ &types.PbmCapabilityProfile{ PbmProfile: types.PbmProfile{ ProfileId: types.PbmProfileId{ @@ -164,55 +217,7 @@ var profiles = []types.BasePbmProfile{ SystemCreatedProfileType: "VVolDefaultProfile", LineOfService: "", }, - &types.PbmCapabilityProfile{ - PbmProfile: types.PbmProfile{ - ProfileId: types.PbmProfileId{ - UniqueId: "4d5f673c-536f-11e6-beb8-9e71128cae77", - }, - Name: "VM Encryption Policy", - Description: "Sample storage policy for VMware's VM and virtual disk encryption", - CreationTime: time.Now(), - CreatedBy: "Temporary user handle", - LastUpdatedTime: time.Now(), - LastUpdatedBy: "Temporary user handle", - }, - ProfileCategory: "REQUIREMENT", - ResourceType: types.PbmProfileResourceType{ - ResourceType: "STORAGE", - }, - Constraints: &types.PbmCapabilitySubProfileConstraints{ - PbmCapabilityConstraints: types.PbmCapabilityConstraints{}, - SubProfiles: []types.PbmCapabilitySubProfile{ - { - Name: "sp-1", - Capability: []types.PbmCapabilityInstance{ - { - Id: types.PbmCapabilityMetadataUniqueId{ - Namespace: "com.vmware.storageprofile.dataservice", - Id: "ad5a249d-cbc2-43af-9366-694d7664fa52", - }, - Constraint: []types.PbmCapabilityConstraintInstance{ - { - PropertyInstance: []types.PbmCapabilityPropertyInstance{ - { - Id: "ad5a249d-cbc2-43af-9366-694d7664fa52", - Operator: "", - Value: "ad5a249d-cbc2-43af-9366-694d7664fa52", - }, - }, - }, - }, - }, - }, - ForceProvision: vim.NewBool(false), - }, - }, - }, - GenerationId: 0, - IsDefault: false, - SystemCreatedProfileType: "", - LineOfService: "", - }, + defaultEncryptionProfile, &types.PbmCapabilityProfile{ PbmProfile: types.PbmProfile{ ProfileId: types.PbmProfileId{ diff --git a/pbm/simulator/simulator.go b/pbm/simulator/simulator.go index 8f4b3fc30..7478b44fa 100644 --- a/pbm/simulator/simulator.go +++ b/pbm/simulator/simulator.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2024 VMware, Inc. 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 +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, @@ -17,6 +17,7 @@ limitations under the License. package simulator import ( + "slices" "time" "github.com/google/uuid" @@ -61,9 +62,11 @@ func New() *simulator.Registry { Content: content, }) - r.Put(&ProfileManager{ + profileManager := &ProfileManager{ ManagedObjectReference: content.ProfileManager, - }) + } + profileManager.init(r) + r.Put(profileManager) r.Put(&PlacementSolver{ ManagedObjectReference: content.PlacementSolver, @@ -88,14 +91,34 @@ func (s *ServiceInstance) PbmRetrieveServiceContent(_ *types.PbmRetrieveServiceC type ProfileManager struct { vim.ManagedObjectReference + + profiles []types.BasePbmProfile + profileDetails map[string]types.PbmProfileDetails +} + +func (m *ProfileManager) init(_ *simulator.Registry) { + m.profiles = slices.Clone(vcenter67DefaultProfiles) + + // Ensure the default encryption profile has the encryption IOFILTER as this + // is required when detecting whether a policy supports encryption. + m.profileDetails = map[string]types.PbmProfileDetails{ + defaultEncryptionProfile.ProfileId.UniqueId: { + Profile: defaultEncryptionProfile, + IofInfos: []types.PbmIofilterInfo{ + { + FilterType: string(types.PbmIofilterInfoFilterTypeENCRYPTION), + }, + }, + }, + } } func (m *ProfileManager) PbmQueryProfile(req *types.PbmQueryProfile) soap.HasFault { body := new(methods.PbmQueryProfileBody) body.Res = new(types.PbmQueryProfileResponse) - for i := range profiles { - b, ok := profiles[i].(types.BasePbmCapabilityProfile) + for i := range m.profiles { + b, ok := m.profiles[i].(types.BasePbmCapabilityProfile) if !ok { continue } @@ -143,7 +166,7 @@ func (m *ProfileManager) PbmRetrieveContent(req *types.PbmRetrieveContent) soap. var res []types.BasePbmProfile match := func(id string) bool { - for _, p := range profiles { + for _, p := range m.profiles { if id == p.GetPbmProfile().ProfileId.UniqueId { res = append(res, p) return true @@ -191,7 +214,7 @@ func (m *ProfileManager) PbmCreate(ctx *simulator.Context, req *types.PbmCreate) LineOfService: "", } - profiles = append(profiles, profile) + m.profiles = append(m.profiles, profile) body.Res.Returnval.UniqueId = profile.PbmProfile.ProfileId.UniqueId return body @@ -201,11 +224,11 @@ func (m *ProfileManager) PbmDelete(req *types.PbmDelete) soap.HasFault { body := new(methods.PbmDeleteBody) for _, id := range req.ProfileId { - for i, p := range profiles { + for i, p := range m.profiles { pid := p.GetPbmProfile().ProfileId if id == pid { - profiles = append(profiles[:i], profiles[i+1:]...) + m.profiles = append(m.profiles[:i], m.profiles[i+1:]...) break } } @@ -216,6 +239,33 @@ func (m *ProfileManager) PbmDelete(req *types.PbmDelete) soap.HasFault { return body } +func (m *ProfileManager) PbmQueryIOFiltersFromProfileId(req *types.PbmQueryIOFiltersFromProfileId) soap.HasFault { + body := methods.PbmQueryIOFiltersFromProfileIdBody{ + Res: &types.PbmQueryIOFiltersFromProfileIdResponse{}, + } + + for i := range req.ProfileIds { + profileID := req.ProfileIds[i] + if profileDetails, ok := m.profileDetails[profileID.UniqueId]; ok { + body.Res.Returnval = append( + body.Res.Returnval, + types.PbmProfileToIofilterMap{ + Key: profileID, + Iofilters: profileDetails.IofInfos, + }) + } else { + body.Fault_ = simulator.Fault("Invalid profile ID", &vim.RuntimeFault{}) + break + } + } + + if body.Fault_ != nil { + body.Res = nil + } + + return &body +} + type PlacementSolver struct { vim.ManagedObjectReference } diff --git a/pbm/simulator/simulator_test.go b/pbm/simulator/simulator_test.go index 1ff82f711..a8198c415 100644 --- a/pbm/simulator/simulator_test.go +++ b/pbm/simulator/simulator_test.go @@ -172,22 +172,22 @@ func TestSimulator(t *testing.T) { Description: "VSAN Test policy create", Category: string(types.PbmProfileCategoryEnumREQUIREMENT), CapabilityList: []pbm.Capability{ - pbm.Capability{ + { ID: "hostFailuresToTolerate", Namespace: "VSAN", PropertyList: []pbm.Property{ - pbm.Property{ + { ID: "hostFailuresToTolerate", Value: "2", DataType: "int", }, }, }, - pbm.Capability{ + { ID: "stripeWidth", Namespace: "VSAN", PropertyList: []pbm.Property{ - pbm.Property{ + { ID: "stripeWidth", Value: "1", DataType: "int", @@ -247,32 +247,32 @@ func TestSimulator(t *testing.T) { Description: "VSAN-SIOC-Test policy create", Category: string(types.PbmProfileCategoryEnumREQUIREMENT), CapabilityList: []pbm.Capability{ - pbm.Capability{ + { ID: "stripeWidth", Namespace: "VSAN", PropertyList: []pbm.Property{ - pbm.Property{ + { ID: "stripeWidth", Value: "1", DataType: "int", }, }, }, - pbm.Capability{ + { ID: "spm@DATASTOREIOCONTROL", Namespace: "spm", PropertyList: []pbm.Property{ - pbm.Property{ + { ID: "limit", Value: "200", DataType: "int", }, - pbm.Property{ + { ID: "reservation", Value: "1000", DataType: "int", }, - pbm.Property{ + { ID: "shares", Value: "2000", DataType: "int", diff --git a/pbm/types/internal_types.go b/pbm/types/internal_types.go new file mode 100644 index 000000000..d166d9dc9 --- /dev/null +++ b/pbm/types/internal_types.go @@ -0,0 +1,95 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. 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 types + +import ( + "reflect" + + "github.com/vmware/govmomi/vim25/types" +) + +type ArrayOfPbmIofilterInfo struct { + PbmIofilterInfo []PbmIofilterInfo `xml:"PbmIofilterInfo,omitempty" json:"_value"` +} + +func init() { + types.Add("pbm:ArrayOfPbmIofilterInfo", reflect.TypeOf((*ArrayOfPbmIofilterInfo)(nil)).Elem()) +} + +type ArrayOfPbmProfileToIofilterMap struct { + PbmProfileToIofilterMap []PbmProfileToIofilterMap `xml:"PbmProfileToIofilterMap,omitempty" json:"_value"` +} + +func init() { + types.Add("pbm:ArrayOfPbmProfileToIofilterMap", reflect.TypeOf((*ArrayOfPbmProfileToIofilterMap)(nil)).Elem()) +} + +type PbmQueryIOFiltersFromProfileId PbmQueryIOFiltersFromProfileIdRequestType + +func init() { + types.Add("pbm:PbmQueryIOFiltersFromProfileId", reflect.TypeOf((*PbmQueryIOFiltersFromProfileId)(nil)).Elem()) +} + +type PbmQueryIOFiltersFromProfileIdRequestType struct { + This types.ManagedObjectReference `xml:"_this" json:"_this"` + ProfileIds []PbmProfileId `xml:"profileIds,typeattr" json:"profileIds"` +} + +func init() { + types.Add("pbm:PbmQueryIOFiltersFromProfileIdRequestType", reflect.TypeOf((*PbmQueryIOFiltersFromProfileIdRequestType)(nil)).Elem()) +} + +type PbmQueryIOFiltersFromProfileIdResponse struct { + Returnval []PbmProfileToIofilterMap `xml:"returnval" json:"returnval"` +} + +type PbmIofilterInfo struct { + types.DynamicData + + VibId string `xml:"vibId" json:"vibId"` + FilterType string `xml:"filterType,omitempty" json:"filterType,omitempty"` +} + +func init() { + types.Add("pbm:PbmIofilterInfo", reflect.TypeOf((*PbmIofilterInfo)(nil)).Elem()) +} + +type PbmProfileToIofilterMap struct { + types.DynamicData + + Key PbmProfileId `xml:"key,typeattr" json:"key"` + Iofilters []PbmIofilterInfo `xml:"iofilters,omitempty" json:"iofilters,omitempty"` + Fault *types.LocalizedMethodFault `xml:"fault,omitempty" json:"fault,omitempty"` +} + +func init() { + types.Add("pbm:PbmProfileToIofilterMap", reflect.TypeOf((*PbmProfileToIofilterMap)(nil)).Elem()) +} + +type PbmProfileDetails struct { + types.DynamicData + + Profile BasePbmCapabilityProfile `xml:"profile,typeattr" json:"profile"` + IofInfos []PbmIofilterInfo `xml:"iofInfos,omitempty" json:"iofInfos,omitempty"` + IofMethodFault *types.LocalizedMethodFault `xml:"iofMethodFault,omitempty" json:"iofMethodFault,omitempty"` + IsReplicationPolicy bool `xml:"isReplicationPolicy" json:"isReplicationPolicy"` + RepMethodFault *types.LocalizedMethodFault `xml:"repMethodFault,omitempty" json:"repMethodFault,omitempty"` +} + +func init() { + types.Add("pbm:PbmProfileDetails", reflect.TypeOf((*PbmProfileDetails)(nil)).Elem()) +}