/
endpointgroup.go
227 lines (191 loc) · 6.93 KB
/
endpointgroup.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
//
// SPDX-License-Identifier: BSD-3-Clause
//
package redfish
import (
"encoding/json"
"reflect"
"github.com/stmcginnis/gofish/common"
)
type GroupType string
const (
// ClientGroupType shall indicate that the endpoint group contains client (initiator) endpoints. If the associated
// endpoints contain the EntityRole property, the EntityRole property shall contain the value 'Initiator' or
// 'Both'.
ClientGroupType GroupType = "Client"
// ServerGroupType shall indicate that the endpoint group contains server (target) endpoints. If the associated
// endpoints contain the EntityRole property, the EntityRole property shall contain the value 'Target' or 'Both'.
ServerGroupType GroupType = "Server"
// InitiatorGroupType shall indicate that the endpoint group contains initiator endpoints. If the associated
// endpoints contain the EntityRole property, the EntityRole property shall contain the value 'Initiator' or
// 'Both'.
InitiatorGroupType GroupType = "Initiator"
// TargetGroupType shall indicate that the endpoint group contains target endpoints. If the associated endpoints
// contain the EntityRole property, the EntityRole property shall contain the value 'Target' or 'Both'.
TargetGroupType GroupType = "Target"
)
// EndpointGroup shall represent a group of endpoints that are managed as a unit for a Redfish implementation.
type EndpointGroup struct {
common.Entity
// ODataContext is the odata context.
ODataContext string `json:"@odata.context"`
// ODataEtag is the odata etag.
ODataEtag string `json:"@odata.etag"`
// ODataType is the odata type.
ODataType string `json:"@odata.type"`
// Description provides a description of this resource.
Description string
// GroupType shall contain the endpoint group type. If this endpoint group represents a SCSI target group, the
// value of this property shall contain 'Server' or 'Target'.
GroupType GroupType
// Identifier shall be unique within the managed ecosystem.
Identifier common.Identifier
// TargetEndpointGroupIdentifier shall contain a SCSI-defined identifier for this group that corresponds to the
// TARGET PORT GROUP field in the REPORT TARGET PORT GROUPS response and the TARGET PORT GROUP field in an INQUIRY
// VPD page 85 response, type 5h identifier. See the INCITS SAM-5 specification. This property may not be present
// if the endpoint group does not represent a SCSI target group.
TargetEndpointGroupIdentifier int
// rawData holds the original serialized JSON so we can compare updates.
rawData []byte
endpoints []string
// EndpointsCount is the number of Endpoints in the group.
EndpointsCount int `json:"Endpoints@odata.count"`
connections []string
// ConnectionsCount is the number of Connections to this group.
ConnectionsCount int
}
// UnmarshalJSON unmarshals a EndpointGroup object from the raw JSON.
func (endpointgroup *EndpointGroup) UnmarshalJSON(b []byte) error {
type temp EndpointGroup
type Links struct {
// Connections shall contain an array of links to resources of type Connection that represent the connections to
// which this endpoint group belongs.
Connections common.Links
ConnectionsCount int `json:"Connections@odata.count"`
// Endpoints shall contain an array of links to resources of type Endpoint that represent the endpoints that are in
// this endpoint group.
Endpoints common.Links
EndpointsCount int `json:"Endpoints@odata.count"`
}
var t struct {
temp
Endpoints common.Links
Links Links
}
err := json.Unmarshal(b, &t)
if err != nil {
return err
}
*endpointgroup = EndpointGroup(t.temp)
// Extract the links to other entities for later
endpointgroup.connections = t.Links.Connections.ToStrings()
endpointgroup.ConnectionsCount = t.Links.ConnectionsCount
// Handle the move of endpoint links in 1.3.0
if len(endpointgroup.endpoints) == 0 {
endpointgroup.endpoints = t.Links.Endpoints.ToStrings()
endpointgroup.EndpointsCount = t.Links.EndpointsCount
}
// This is a read/write object, so we need to save the raw object data for later
endpointgroup.rawData = b
return nil
}
// Update commits updates to this object's properties to the running system.
func (endpointgroup *EndpointGroup) Update() error {
// Get a representation of the object's original state so we can find what
// to update.
original := new(EndpointGroup)
original.UnmarshalJSON(endpointgroup.rawData)
readWriteFields := []string{
"GroupType",
"TargetEndpointGroupIdentifier",
}
originalElement := reflect.ValueOf(original).Elem()
currentElement := reflect.ValueOf(endpointgroup).Elem()
return endpointgroup.Entity.Update(originalElement, currentElement, readWriteFields)
}
// GetEndpointGroup will get a EndpointGroup instance from the service.
func GetEndpointGroup(c common.Client, uri string) (*EndpointGroup, error) {
resp, err := c.Get(uri)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var endpointgroup EndpointGroup
err = json.NewDecoder(resp.Body).Decode(&endpointgroup)
if err != nil {
return nil, err
}
endpointgroup.SetClient(c)
return &endpointgroup, nil
}
// ListReferencedEndpointGroups gets the collection of EndpointGroup from
// a provided reference.
func ListReferencedEndpointGroups(c common.Client, link string) ([]*EndpointGroup, error) {
var result []*EndpointGroup
if link == "" {
return result, nil
}
type GetResult struct {
Item *EndpointGroup
Link string
Error error
}
ch := make(chan GetResult)
collectionError := common.NewCollectionError()
get := func(link string) {
endpointgroup, err := GetEndpointGroup(c, link)
ch <- GetResult{Item: endpointgroup, Link: link, Error: err}
}
go func() {
err := common.CollectList(get, c, link)
if err != nil {
collectionError.Failures[link] = err
}
close(ch)
}()
for r := range ch {
if r.Error != nil {
collectionError.Failures[r.Link] = r.Error
} else {
result = append(result, r.Item)
}
}
if collectionError.Empty() {
return result, nil
}
return result, collectionError
}
// Endpoints get the endpoints associated with this endpoint group.
func (endpointgroup *EndpointGroup) Endpoints() ([]*Endpoint, error) {
var result []*Endpoint
collectionError := common.NewCollectionError()
for _, uri := range endpointgroup.endpoints {
rb, err := GetEndpoint(endpointgroup.GetClient(), uri)
if err != nil {
collectionError.Failures[uri] = err
} else {
result = append(result, rb)
}
}
if collectionError.Empty() {
return result, nil
}
return result, collectionError
}
// Connections get the connections associated with this endpoint group.
func (endpointgroup *EndpointGroup) Connections() ([]*Connection, error) {
var result []*Connection
collectionError := common.NewCollectionError()
for _, uri := range endpointgroup.connections {
rb, err := GetConnection(endpointgroup.GetClient(), uri)
if err != nil {
collectionError.Failures[uri] = err
} else {
result = append(result, rb)
}
}
if collectionError.Empty() {
return result, nil
}
return result, collectionError
}