Skip to content

Commit ec34903

Browse files
committed
Merge remote-tracking branch 'origin/main' into hl_igrp
# Conflicts: # descriptions/descriptions.go # ontap/ontap.go # server/server.go # tool/tool.go
2 parents 291c6c0 + f3c7f07 commit ec34903

9 files changed

Lines changed: 730 additions & 1 deletion

File tree

descriptions/descriptions.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ const CreateNVMeService = `Create NVMe service on a cluster by cluster name.`
7676
const UpdateNVMeService = `Update NVMe service on a cluster by cluster name.`
7777
const DeleteNVMeService = `Delete NVMe service on a cluster by cluster name.`
7878

79+
const CreateIscsiService = `Create iSCSI service on a cluster by cluster name.`
80+
const UpdateIscsiService = `Update iSCSI service on a cluster by cluster name.`
81+
const DeleteIscsiService = `Delete iSCSI service on a cluster by cluster name.`
82+
83+
const CreateNetworkIPInterface = `Create Network IP interface on a cluster by cluster name.`
84+
const UpdateNetworkIPInterface = `Update Network IP interface on a cluster by cluster name.`
85+
const DeleteNetworkIPInterface = `Delete Network IP interface on a cluster by cluster name.`
86+
7987
const CreateIGroup = `Create an igroup (initiator group) on a cluster by cluster name.`
8088
const UpdateIGroup = `Update an igroup on a cluster by cluster name.`
8189
const DeleteIGroup = `Delete an igroup on a cluster by cluster name.`

docs/examples.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,34 @@ Expected Response: The nvme service has been successfully updated.
263263

264264
---
265265

266+
### Manage iSCSI Service
267+
268+
- On the umeng-aff300-05-06 cluster, create iscsi service target named alias tgpath on the marketing svm
269+
270+
Expected Response: The iscsi service has been successfully created.
271+
272+
- On the umeng-aff300-05-06 cluster, disable the iscsi service on the marketing svm
273+
274+
Expected Response: The iscsi service has been successfully updated.
275+
276+
- On the umeng-aff300-05-06 cluster, delete the iscsi service on the marketing svm
277+
278+
Expected Response: The iscsi service has been successfully deleted.
279+
280+
- on the umeng-aff300-05-06 cluster, create network interface named cl_mg with ip address 10.63.41.6 and netmask 18 with Default ipspace on node umeng-aff300-06
281+
282+
Expected Response: The Network IP interface has been created successfully.
283+
284+
- on the umeng-aff300-05-06 cluster, change auto revert to false in cluster scope network interface named cl_mg
285+
286+
Expected Response: The Network IP interface updated successfully.
287+
288+
- on the umeng-aff300-05-06 cluster, delete svm scope network interface named svg1 in marketing svm
289+
290+
Expected Response: The Network IP interface deleted successfully.
291+
292+
---
293+
266294
### Querying Specific Fields
267295

268296
**Get volume space and protection details**

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/netapp/ontap-mcp
22

3-
go 1.26.1
3+
go 1.26.2
44

55
require (
66
github.com/alecthomas/kong v1.14.0

integration/test/iscsi_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"crypto/tls"
6+
"log/slog"
7+
"net/http"
8+
"testing"
9+
"time"
10+
11+
"github.com/netapp/ontap-mcp/config"
12+
)
13+
14+
func TestIscsiProtocol(t *testing.T) {
15+
SkipIfMissing(t, CheckTools)
16+
17+
tests := []struct {
18+
name string
19+
input string
20+
expectedOntapErr string
21+
verifyAPI ontapVerifier
22+
}{
23+
{
24+
name: "Clean iSCSI service",
25+
input: ClusterStr + "delete iscsi service in marketing svm",
26+
expectedOntapErr: "because it does not exist",
27+
verifyAPI: ontapVerifier{api: "api/protocols/san/iscsi/services?svm.name=marketing", validationFunc: deleteObject},
28+
},
29+
{
30+
name: "Create iSCSI service",
31+
input: ClusterStr + "create iscsi service target named alias " + rn("tgpath") + " on the marketing svm",
32+
expectedOntapErr: "",
33+
verifyAPI: ontapVerifier{api: "api/protocols/san/iscsi/services?svm.name=marketing", validationFunc: createObject},
34+
},
35+
{
36+
name: "Clean cluster scope network interface",
37+
input: ClusterStr + "delete cluster scope network interface named " + rn("cl_mg"),
38+
expectedOntapErr: "because it does not exist",
39+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("cl_mg") + "&scope=cluster", validationFunc: deleteObject},
40+
},
41+
{
42+
name: "Clean svm scope network interface",
43+
input: ClusterStr + "delete svm scope network interface named " + rn("svg1") + " in marketing svm",
44+
expectedOntapErr: "because it does not exist",
45+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("svg1") + "&scope=svm", validationFunc: deleteObject},
46+
},
47+
{
48+
name: "Create cluster scope network interface with IP",
49+
input: ClusterStr + "create network interface named " + rn("cl_mg") + " with ip address 10.63.41.6 and netmask 18 with Default ipspace on node umeng-aff300-06",
50+
expectedOntapErr: "",
51+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("cl_mg") + "&scope=cluster", validationFunc: createObject},
52+
},
53+
{
54+
name: "Create svm scope network interface with ip",
55+
input: ClusterStr + "create network interface named " + rn("svg1") + " in marketing svm with ip address 10.63.41.7 and netmask 18 on node umeng-aff300-06",
56+
expectedOntapErr: "",
57+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("svg1") + "&scope=svm", validationFunc: createObject},
58+
},
59+
{
60+
name: "Clean cluster scope network interface",
61+
input: ClusterStr + "delete cluster scope network interface named " + rn("cl_mg"),
62+
expectedOntapErr: "because it does not exist",
63+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("cl_mg") + "&scope=cluster", validationFunc: deleteObject},
64+
},
65+
{
66+
name: "Clean svm scope network interface",
67+
input: ClusterStr + "delete svm scope network interface named " + rn("svg1") + " in marketing svm",
68+
expectedOntapErr: "because it does not exist",
69+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("svg1") + "&scope=svm", validationFunc: deleteObject},
70+
},
71+
{
72+
name: "Create svm scope network interface with broadcast domain",
73+
input: ClusterStr + "create network interface named " + rn("svg1") + " in marketing svm with ip address 10.63.41.7 and netmask 18 on broadcast domain as Default",
74+
expectedOntapErr: "",
75+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("svg1") + "&scope=svm", validationFunc: createObject},
76+
},
77+
{
78+
name: "Clean svm scope network interface with broadcast domain",
79+
input: ClusterStr + "delete svm scope network interface named " + rn("svg1") + " in marketing svm",
80+
expectedOntapErr: "because it does not exist",
81+
verifyAPI: ontapVerifier{api: "api/network/ip/interfaces?name=" + rn("svg1") + "&scope=svm", validationFunc: deleteObject},
82+
},
83+
{
84+
name: "Update iSCSI service",
85+
input: ClusterStr + "disabled iscsi service on the marketing svm",
86+
expectedOntapErr: "",
87+
verifyAPI: ontapVerifier{},
88+
},
89+
{
90+
name: "Clean iSCSI service",
91+
input: ClusterStr + "delete iscsi service in marketing svm",
92+
expectedOntapErr: "because it does not exist",
93+
verifyAPI: ontapVerifier{api: "api/protocols/san/iscsi/services?svm.name=marketing", validationFunc: deleteObject},
94+
},
95+
}
96+
97+
cfg, err := config.ReadConfig(ConfigFile)
98+
if err != nil {
99+
t.Fatalf("Error parsing the config: %v", err)
100+
}
101+
102+
poller := cfg.Pollers[Cluster]
103+
transport := &http.Transport{
104+
TLSClientConfig: &tls.Config{
105+
InsecureSkipVerify: poller.UseInsecureTLS, // #nosec G402
106+
},
107+
}
108+
client := &http.Client{Transport: transport, Timeout: 10 * time.Second}
109+
110+
for _, tt := range tests {
111+
t.Run(tt.name, func(t *testing.T) {
112+
slog.Debug("", slog.String("Input", tt.input))
113+
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
114+
defer cancel()
115+
if _, err = testAgent.ChatWithResponse(ctx, t, tt.input, tt.expectedOntapErr); err != nil {
116+
slog.Error("Error processing input", slog.Any("error", err))
117+
}
118+
if tt.verifyAPI.api != "" && !tt.verifyAPI.validationFunc(t, tt.verifyAPI.api, poller, client) {
119+
t.Errorf("Error while accessing the object via prompt %s", tt.input)
120+
}
121+
})
122+
}
123+
}

ontap/ontap.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ type NASExportPolicy struct {
6464
Name string `json:"name"`
6565
}
6666

67+
type Target struct {
68+
Alias string `json:"alias"`
69+
}
70+
71+
type IP struct {
72+
Address string `json:"address" jsonschema:"IP address for the interface"`
73+
Netmask string `json:"netmask" jsonschema:"IP netmask for the interface"`
74+
}
75+
76+
type Location struct {
77+
HomeNode NameAndUUID `json:"home_node,omitzero" jsonschema:"home node"`
78+
BroadcastDomain NameAndUUID `json:"broadcast_domain,omitzero" jsonschema:"broadcast domain"`
79+
AutoRevert string `json:"auto_revert,omitzero" jsonschema:"auto revert"`
80+
}
81+
6782
type NAS struct {
6883
ExportPolicy NASExportPolicy `json:"export_policy,omitzero"`
6984
Path string `json:"path,omitzero"`
@@ -194,6 +209,23 @@ type NVMeService struct {
194209
Enabled string `json:"enabled,omitzero" jsonschema:"admin state of the NVMe service"`
195210
}
196211

212+
type IscsiService struct {
213+
SVM NameAndUUID `json:"svm,omitzero" jsonschema:"svm name"`
214+
Enabled string `json:"enabled,omitzero" jsonschema:"admin state of the iSCSI service"`
215+
Target Target `json:"target,omitzero" jsonschema:"target of iSCSI service"`
216+
}
217+
218+
type NetworkIPInterface struct {
219+
SVM NameAndUUID `json:"svm,omitzero" jsonschema:"svm name"`
220+
IPSpace NameAndUUID `json:"ipspace,omitzero" jsonschema:"ipspace name"`
221+
Name string `json:"name" jsonschema:"name of the interface"`
222+
Scope string `json:"scope,omitzero" jsonschema:"scope"` // enum: cluster, svm
223+
IP IP `json:"ip,omitzero" jsonschema:"ip address"`
224+
Subnet NameAndUUID `json:"subnet,omitzero" jsonschema:"subnet name"`
225+
Location Location `json:"location,omitzero" jsonschema:"location name"`
226+
ServicePolicy NameAndUUID `json:"service_policy,omitzero" jsonschema:"service policy"`
227+
}
228+
197229
type InitiatorName struct {
198230
Name string `json:"name,omitzero" jsonschema:"The FC WWPN, iSCSI IQN, or iSCSI EUI that identifies the host initiator."`
199231
}

0 commit comments

Comments
 (0)