aviz-sonic-rbapi 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2019, Aviz Networks. All rights reserved.
3
+ #
4
+ # This program and the accompanying materials are licensed and made available
5
+ # under the terms and conditions of the 3-clause BSD License that accompanies
6
+ # this distribution.
7
+ #
8
+ # The full text of the license may be found at
9
+ #
10
+ # https://opensource.org/licenses/BSD-3-Clause
11
+ #
12
+ # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
+ require 'rest-client'
15
+ require 'json'
16
+ require_relative 'connect'
17
+ require_relative 'rest_utils'
18
+
19
+ # The Portchnl class provides a class implementation and methods for managing Portchannel
20
+ # on the node. This class presents an abstraction
21
+
22
+ class Portchnl
23
+ @portchnl_cfg = '/api/portchnls/cfgs'
24
+ @portchnl_info = '/api/portchnls/info'
25
+
26
+ # This API gets the portchannel information.
27
+ #
28
+ # Request URL: http://IP-ADDR:REST-PORT/api/portchnls/info/summary - Get PortChannel summary information
29
+ # http://IP-ADDR:REST-PORT/api/portchnls/info/state - Get Portchannel state information
30
+ #
31
+ # @param conn [Class] Connect object to the node
32
+ # @param filter [String] String to get PortChannel summary or state
33
+ # @param pch_id [Integer] Portchannel Id
34
+ #
35
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
36
+ # {
37
+ # "PortChannelName": {
38
+ # "admin_status": "up",
39
+ # "oper_status": "down",
40
+ # "mtu": "9100",
41
+ # "members": {
42
+ # ":Interface": {
43
+ # "status": "Active or Inactive or Up or Down"
44
+ # }
45
+ # }
46
+ # }
47
+ # {
48
+ # “Member Name1”:{
49
+ # "info": {
50
+ # "dev_addr": "mac",
51
+ # "ifindex": ,
52
+ # },
53
+ # "actor_lacpdu_info": {
54
+ # "key": ,
55
+ # "port":,
56
+ # "port_priority":,
57
+ # "state": 0,
58
+ # "system": "a4:8c:db:b9:c4:00",
59
+ # "system_priority": 65535
60
+ # },
61
+ # "partner_lacpdu_info": {
62
+ # "key": 0,
63
+ # "port": 0,
64
+ # "port_priority": 0,
65
+ # "state": 0,
66
+ # "system": "00:00:00:00:00:00",
67
+ # "system_priority": 0
68
+ # },
69
+ # "aggregator": {
70
+ # "id": 0,
71
+ # "selected": false
72
+ # },
73
+ # },
74
+ # “Member Name2”:{
75
+ # },
76
+ # ………..
77
+ # }
78
+ def self.get_portchnl_info(conn, filter, pch_id=nil)
79
+ if pch_id != nil
80
+ url = form_url(conn, @portchnl_info + '/' + filter + '/PortChannel' + pch_id.to_s)
81
+ else
82
+ url = form_url(conn, @portchnl_info + '/' + filter)
83
+ end
84
+ hdr = form_hdr(conn)
85
+ Rest.get(conn, url, hdr)
86
+ end
87
+
88
+ # This API creates a portchannel.
89
+ #
90
+ # Request URL: http://IP-ADDR:REST-PORT/api/portchnls/cfgs/10
91
+ # payload format of key-value pairs
92
+ # {
93
+ # "admin_status": "up",
94
+ # "mtu": 9100,
95
+ # "fallback": true
96
+ # }
97
+ #
98
+ # @param conn [Class] Connect object to the node
99
+ # @param pch_id [Integer] Portchannel id
100
+ # @param admin_status [String] Admin status of the port-channel. Valid values "up" or "down"
101
+ # @param mtu [Integer] Max transmission unit. Valid Values: 1500-9100
102
+ # @param fallback [Boolean] Fallback value "true" or "false"
103
+ #
104
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
105
+ def self.create_portchnl(conn, pch_id, admin_status='up', mtu=9100, fallback='false')
106
+ url = form_url(conn, @portchnl_cfg + '/' + pch_id.to_s)
107
+ hdr = form_hdr(conn)
108
+ params = {"admin_status": admin_status, "mtu": mtu, "fallback": fallback}
109
+ params = params.to_json
110
+ Rest.post(conn, url, hdr, params)
111
+ end
112
+
113
+ # This API updates the properties of a particular portchannel.
114
+ #
115
+ # Request URL: http://IP-ADDR:REST-PORT/api/portchnls/cfgs/10
116
+ # payload format of key-value pairs
117
+ # {
118
+ # "add_member": ["Ethernet0", "Ethernet4"],
119
+ # "rem_member": ["Ethernet12"]
120
+ # }
121
+ #
122
+ # @param conn [Class] Connect object to the node
123
+ # @param pch_id [Integer] Portchannel id
124
+ # @param add_members [Array] List of ports to be added to the portchnl
125
+ # @param rem_members [Array] List of ports to be removed from the portchnl
126
+ #
127
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
128
+ def self.update_portchnl_members(conn, pch_id, add_members=nil, rem_members=nil)
129
+ url = form_url(conn, @portchnl_cfg + '/' + pch_id.to_s)
130
+ hdr = form_hdr(conn)
131
+ if add_members == nil || rem_members == nil
132
+ puts("update_portchnl_members: wrong paramers\n")
133
+ end
134
+ params = {"add_member": add_members}
135
+ p1 = {"rem_member": rem_members}
136
+ params = params.merge(p1)
137
+ params = params.to_json
138
+ Rest.put(conn, url, hdr, params)
139
+ end
140
+
141
+ # This API gets all the portchannel startup configuration.
142
+ #
143
+ # Request URL: http://IP-ADDR:REST-PORT/api/portchnls/cfgs
144
+ #
145
+ # @param conn [Class] Connect object to the node
146
+ #
147
+ # @return [RestClient::Request] Rest output from SONIC in JSON format as below
148
+ # {
149
+ # "PortChannel200": {
150
+ # "members": ["Ethernet8", "Ethernet32", "Ethernet16"],
151
+ # "mtu": "9100",
152
+ # "admin_status": "up",
153
+ # "fallback": "true",
154
+ # },
155
+ # }
156
+ def self.get_portchnl_cfg(conn)
157
+ url = form_url(conn, @portchnl_cfg)
158
+ hdr = form_hdr(conn)
159
+ Rest.get(conn, url, hdr)
160
+ end
161
+
162
+ # This API deletes specified portchannel.
163
+ #
164
+ # Request URL: http://IP-ADDR:REST-PORT/api/portchnls/cfgs/10
165
+ #
166
+ # @param conn [Class] Connect object to the node
167
+ # @param pch_id [Integer] Portchannel Id
168
+ #
169
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
170
+ def self.delete_portchnl(conn, pch_id)
171
+ url = form_url(conn, @portchnl_cfg + '/' + pch_id.to_s)
172
+ hdr = form_hdr(conn)
173
+ Rest.delete(conn, url, hdr)
174
+ end
175
+ end
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2019, Aviz Networks. All rights reserved.
3
+ #
4
+ # This program and the accompanying materials are licensed and made available
5
+ # under the terms and conditions of the 3-clause BSD License that accompanies
6
+ # this distribution.
7
+ #
8
+ # The full text of the license may be found at
9
+ #
10
+ # https://opensource.org/licenses/BSD-3-Clause
11
+ #
12
+ # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
+ require 'rest-client'
15
+ require 'json'
16
+
17
+ # The Rest class provides a class implementation and methods for executing REST methods such as GET, POST, PUT and DELETE
18
+ # on the node. This class presents an abstraction
19
+
20
+ class Rest
21
+
22
+ # This API performs REST GET request for the given url with switch credentials.
23
+ #
24
+ # @param conn [Class] Connect object to the node
25
+ # @param url [String] URL for the GET request
26
+ # @param hdr [String] Header parameters for the GET request
27
+ #
28
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
29
+ def self.get(conn, url, hdr)
30
+ begin
31
+ Log.file.puts("\n--------------------- GET --------------------- ", url, hdr)
32
+ resp = RestClient::Request.execute method: :get, url: url, headers: hdr, user: conn.getUser, password: conn.getPassword, timeout: 20 ,:verify_ssl => false
33
+ if resp != ''
34
+ Log.file.puts("RESPONSE - ", resp)
35
+ response = JSON.parse(resp)
36
+ response
37
+ else
38
+ Log.file.puts("RESPONSE - empty")
39
+ response = {}
40
+ response
41
+ end
42
+ rescue RestClient::ExceptionWithResponse => err
43
+ Log.file.puts("ERROR: ")
44
+ Log.file.puts err
45
+ Log.file.puts err.response
46
+ end
47
+ end
48
+
49
+ # This API performs REST PUT request for the given url with switch credentials.
50
+ #
51
+ # @param conn [Class] Connect object to the node
52
+ # @param url [String] URL for the PUT request
53
+ # @param hdr [String] Header parameters for the PUT request
54
+ # @param params [String] JSON body for PUT request
55
+ #
56
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
57
+ def self.put(conn, url, hdr, params)
58
+ begin
59
+ Log.file.puts("\n--------------------- PUT --------------------- ", url, hdr, params)
60
+ resp = RestClient::Request.execute method: :put, url: url, headers: hdr, payload: params, user: conn.getUser, password: conn.getPassword, timeout: 20 ,:verify_ssl => false
61
+ # REST API PUT always gets empty response for success
62
+ if resp != ''
63
+ Log.file.puts("RESPONSE - ", resp)
64
+ response = JSON.parse(resp)
65
+ response
66
+ else
67
+ Log.file.puts("RESPONSE - empty")
68
+ response = {}
69
+ response
70
+ end
71
+ rescue RestClient::ExceptionWithResponse => err
72
+ Log.file.puts("ERROR: ")
73
+ Log.file.puts err
74
+ Log.file.puts err.response
75
+ end
76
+ end
77
+
78
+ # This API performs POST request for the given url with switch credentials.
79
+ #
80
+ # @param conn [Class] Connect object to the node
81
+ # @param url [String] URL for the POST request
82
+ # @param hdr [String] Header parameters for the POST request
83
+ # @param params [String] JSON body for POST request
84
+ #
85
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
86
+ def self.post(conn, url, hdr, params)
87
+ begin
88
+ Log.file.puts("\n--------------------- POST --------------------- ", url, hdr, params)
89
+ resp = RestClient::Request.execute method: :post, url: url, headers: hdr, payload: params, user: conn.getUser, password: conn.getPassword, timeout: 20 ,:verify_ssl => false
90
+ # REST API POST always gets '{}' response for success
91
+ if resp != ''
92
+ Log.file.puts("RESPONSE - ", resp)
93
+ response = JSON.parse(resp)
94
+ response
95
+ else
96
+ Log.file.puts("RESPONSE - empty")
97
+ response = {}
98
+ response
99
+ end
100
+ rescue RestClient::ExceptionWithResponse => err
101
+ Log.file.puts("ERROR: ")
102
+ Log.file.puts err
103
+ Log.file.puts err.response
104
+ end
105
+ end
106
+
107
+ # This API performs DELETE request for the given url with switch credentials.
108
+ #
109
+ # @param conn [Class] Connect object to the node
110
+ # @param url [String] URL for the DELETE request
111
+ # @param hdr [String] Header parameters for the DELETE request
112
+ #
113
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
114
+ def self.delete(conn, url, hdr)
115
+ begin
116
+ Log.file.puts("\n--------------------- DELETE --------------------- ", url, hdr)
117
+ resp = RestClient::Request.execute method: :delete, url: url, headers: hdr, user: conn.getUser, password: conn.getPassword, timeout: 20 ,:verify_ssl => false
118
+ # REST API DELETE always gets empty response for success
119
+ if resp != ''
120
+ Log.file.puts("RESPONSE - ", resp)
121
+ response = JSON.parse(resp)
122
+ response
123
+ else
124
+ Log.file.puts("RESPONSE - empty")
125
+ response = {}
126
+ response
127
+ end
128
+ rescue RestClient::ExceptionWithResponse => err
129
+ Log.file.puts("ERROR: ")
130
+ Log.file.puts err
131
+ Log.file.puts err.response
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2019, Aviz Networks. All rights reserved.
3
+ #
4
+ # This program and the accompanying materials are licensed and made available
5
+ # under the terms and conditions of the 3-clause BSD License that accompanies
6
+ # this distribution.
7
+ #
8
+ # The full text of the license may be found at
9
+ #
10
+ # https://opensource.org/licenses/BSD-3-Clause
11
+ #
12
+ # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
+ require 'rest-client'
15
+ require 'json'
16
+ require_relative 'connect'
17
+ require_relative 'rest_utils'
18
+
19
+ # The System class provides a class implementation and methods for managing and setting up
20
+ # system configuration and images. This class presents an abstraction
21
+
22
+ class System
23
+ @system_cfg = '/api/devices'
24
+
25
+ # This API gets the system meta data parameters
26
+ #
27
+ # Request URL: http://IP-ADDR:REST-PORT/api/devices
28
+ #
29
+ # @param conn [Class] Connect object to the node
30
+ #
31
+ # @return [RestClient::Request] Rest output from SONIC in JSON format as below
32
+ # {
33
+ # "mac": "b4:8c:db:b9:a0:00",
34
+ # "hwsku": "YYY",
35
+ # "hostname": "<string>",
36
+ # "platform": "x86_64",
37
+ # "version": <sonic-version>,
38
+ # "ASIC": <asic-type>
39
+ # "type": "LeafRouter"
40
+ # ...
41
+ # }
42
+ def self.get_system_data(conn)
43
+ url = form_url(conn, @system_cfg)
44
+ hdr = form_hdr(conn)
45
+ Rest.get(conn, url, hdr)
46
+ end
47
+
48
+ # This API updates system mac_addr and hostname
49
+ #
50
+ # Request URL: http://IP-ADDR:REST-PORT/api/devices
51
+ # payload format of key-value pairs
52
+ # {
53
+ # "mac_addr": "00:01:02:03:04:05",
54
+ # "hostname": "hostname"
55
+ # }
56
+ #
57
+ # @param conn [Class] Connect object to the node
58
+ # @param mac_addr [String] Base MAC address of the system
59
+ # @param hostname [String] Hostname of the system
60
+ #
61
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
62
+ def self.update_system_data(conn, mac_addr=nil, hostname=nil)
63
+ url = form_url(conn, @system_cfg)
64
+ hdr = form_hdr(conn)
65
+ if mac_addr != nil
66
+ params = {"mac_addr": mac_addr}
67
+ end
68
+ if hostname != nil
69
+ p1 = {"hostname": hostname}
70
+ if mac_addr != nil
71
+ params = params.merge(p1)
72
+ else
73
+ params = p1
74
+ end
75
+ end
76
+ params = params.to_json
77
+ Rest.put(conn, url, hdr, params)
78
+ end
79
+
80
+ # This API download and install system image
81
+ #
82
+ # Request URL: http://IP-ADDR:REST-PORT/api/devices
83
+ # payload format of key-value pairs
84
+ # {
85
+ # "image_url": "image_url"
86
+ # }
87
+ #
88
+ # @param conn [Class] Connect object to the node
89
+ # @param image_url [String] URL to download system image from remote Web server (http ot https)
90
+ #
91
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
92
+ def self.download_system_img(conn, image_url)
93
+ url = form_url(conn, @system_cfg)
94
+ hdr = form_hdr(conn)
95
+ params = {"image_url": image_url}
96
+ params = params.to_json
97
+ Rest.post(conn, url, hdr, params)
98
+ end
99
+ end
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2019, Aviz Networks. All rights reserved.
3
+ #
4
+ # This program and the accompanying materials are licensed and made available
5
+ # under the terms and conditions of the 3-clause BSD License that accompanies
6
+ # this distribution.
7
+ #
8
+ # The full text of the license may be found at
9
+ #
10
+ # https://opensource.org/licenses/BSD-3-Clause
11
+ #
12
+ # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
+ require 'rest-client'
15
+ require 'json'
16
+ require_relative 'connect'
17
+ require_relative 'rest_utils'
18
+
19
+ # The Vlan class provides a class implementation and methods for managing the VLANs
20
+ # on the node. This class presents an abstraction
21
+
22
+ class Vlan
23
+ @vlan_cfg = '/api/vlans/cfgs'
24
+ @vlan_info = '/api/vlans/info'
25
+
26
+ # This API get the properties of all VLANs.
27
+ #
28
+ # Request URL: http://IP-ADDR:REST-PORT/api/vlans/info
29
+ #
30
+ # @param conn [Class] Connect object to the node
31
+ #
32
+ # @return [RestClient::Request] Rest output from SONIC in JSON format as below
33
+ # {"Vlan_name": {"vlan_id": 100,
34
+ # "members": {"Ethernet16": "tagged", ...}
35
+ # },
36
+ # {"vlan_id": 200,
37
+ # "members": {"Ethernet17": "tagged", ...}
38
+ # },
39
+ # ...
40
+ # }
41
+ def self.get_all_vlan(conn)
42
+ url = form_url(conn, @vlan_info)
43
+ hdr = form_hdr(conn)
44
+ Rest.get(conn, url, hdr)
45
+ end
46
+
47
+ # This API get the properties of single vlan.
48
+ #
49
+ # Request URL: http://IP-ADDR:REST-PORT/api/vlans/info/100
50
+ #
51
+ # @param conn [Class] Connect object to the node
52
+ # @param vlan_id [Integer] VLAN number
53
+ #
54
+ # @return [RestClient::Request] Rest output from SONIC in JSON format as below
55
+ # {"Vlan_name": {"vlan_id": 100,
56
+ # "members": {"Ethernet16": "tagged", ...}
57
+ # },
58
+ # }
59
+ def self.get_vlan(conn, vlan_id)
60
+ url = form_url(conn, @vlan_info + '/' + vlan_id.to_s)
61
+ hdr = form_hdr(conn)
62
+ Rest.get(conn, url, hdr)
63
+ end
64
+
65
+ # This API creates a Vlan.
66
+ #
67
+ # Request URL: http://IP-ADDR:REST-PORT/api/vlans/cfgs/100
68
+ # payload format of key-value pairs
69
+ # {
70
+ # "vlanid": 100,
71
+ # "member": {"InterfaceName1": "tagged", "InterfaceName": "untagged"}
72
+ # }
73
+ #
74
+ # @param conn [Class] Connect object to the node.
75
+ # @param vlan_id [Integer] VLAN number from 1-4095.
76
+ # @param add_tagged_members [Array] List of interfaces to be added to the vlan as tagged members
77
+ # @param add_untagged_members [Array] List of iinterfaces to be added to the vlan as untagged members
78
+ #
79
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
80
+ def self.create_vlan(conn, vlan_id, add_tagged_members=nil, add_untagged_members=nil)
81
+ url = form_url(conn, @vlan_cfg + '/' + vlan_id.to_s)
82
+ hdr = form_hdr(conn)
83
+ params = {"vlanid": vlan_id}
84
+ add_members = nil
85
+ for i in 0..add_tagged_members.size-1 do
86
+ tag = {add_tagged_members[i]=> "tagged"}
87
+ if (add_members == nil)
88
+ add_members = tag
89
+ else
90
+ add_members = add_members.merge(tag)
91
+ end
92
+ end
93
+ for i in 0..add_untagged_members.size-1 do
94
+ untag = {add_untagged_members[i]=> "untagged"}
95
+ if (add_members == nil)
96
+ add_members = untag
97
+ else
98
+ add_members = add_members.merge(untag)
99
+ end
100
+ end
101
+ if add_members != nil
102
+ p1 = {"add_member": add_members}
103
+ else
104
+ p1 = {"add_member": {}}
105
+ end
106
+ params = params.merge(p1)
107
+ params = params.to_json
108
+ Rest.post(conn, url, hdr, params)
109
+ end
110
+
111
+ # This API updates properties of a VLAN.
112
+ #
113
+ # Request URL: http://IP-ADDR:REST-PORT/api/vlans/cfgs/100
114
+ # payload format of key-value pairs
115
+ # {
116
+ # "add_member": {"Ethernet0": "tagged", "Ethernet4": "untagged"},
117
+ # "rem_member": ["Ethernet12"],
118
+ # "rem_all": "false"
119
+ # }
120
+ #
121
+ # @param conn [Class] Connect object to the node
122
+ # @param vlan_id [Integer] VLAN number from 1-4095
123
+ # @param add_tagged_members [Array] List of interfaces to be added to the vlan as tagged members
124
+ # @param add_untagged_members [Array] List of iinterfaces to be added to the vlan as untagged members
125
+ # @param rem_members [Array] List of interfaces to be removed from the vlan
126
+ # @param rem_all [Boolean] A flag to remove all members of the Vlan or not ('true or 'false')
127
+ #
128
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
129
+ def self.update_vlan(conn, vlan_id, add_tagged_members=nil, add_untagged_members=nil, rem_members=nil, rem_all='false')
130
+ url = form_url(conn, @vlan_cfg + '/' + vlan_id.to_s)
131
+ hdr = form_hdr(conn)
132
+ add_members = nil
133
+ params = nil
134
+ for i in 0..add_tagged_members.size-1 do
135
+ tag = {add_tagged_members[i]=> "tagged"}
136
+ if (add_members == nil)
137
+ add_members = tag
138
+ else
139
+ add_members = add_members.merge(tag)
140
+ end
141
+ end
142
+ for i in 0..add_untagged_members.size-1 do
143
+ untag = {add_untagged_members[i]=> "untagged"}
144
+ if (add_members == nil)
145
+ add_members = untag
146
+ else
147
+ add_members = add_members.merge(untag)
148
+ end
149
+ end
150
+ if add_members != nil
151
+ params = {"add_member": add_members}
152
+ else
153
+ params = {"add_member": {}}
154
+ end
155
+ p1 = {"rem_member": rem_members}
156
+ params = params.merge(p1)
157
+ p2 = {"rem_all": rem_all}
158
+ params = params.merge(p2)
159
+ params = params.to_json
160
+ Rest.put(conn, url, hdr, params)
161
+ end
162
+
163
+ # This API deletes a vlan.
164
+ #
165
+ # Request URL: http://IP-ADDR:REST-PORT/api/vlans/cfgs/100
166
+ #
167
+ # @param conn [Class] Connect object to the node
168
+ # @param vlan_id [Integer] VLAN number from 1-4095
169
+ #
170
+ # @return [RestClient::Request] Rest output from SONIC in JSON format
171
+ def self.delete_vlan(conn, vlan_id)
172
+ url = form_url(conn, @vlan_cfg + '/' + vlan_id.to_s)
173
+ hdr = form_hdr(conn)
174
+ Rest.delete(conn, url, hdr)
175
+ end
176
+ end