forked from scottdware/go-junos
-
Notifications
You must be signed in to change notification settings - Fork 1
/
software.go
190 lines (163 loc) · 5.45 KB
/
software.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
package junos
import (
"encoding/xml"
"fmt"
"github.com/scottdware/go-rested"
)
// SoftwarePackages contains a list of software packages managed by Junos Space.
type SoftwarePackages struct {
Packages []SoftwarePackage `xml:"package"`
}
// A SoftwarePackage contains information about each individual software package.
type SoftwarePackage struct {
ID int `xml:"key,attr"`
Name string `xml:"fileName"`
Version string `xml:"version"`
Platform string `xml:"platformType"`
}
// SoftwareUpgrade consists of options available to use before issuing a software upgrade.
type SoftwareUpgrade struct {
UseDownloaded bool // Use an image already staged on the device.
Validate bool // Check/don't check compatibility with current configuration.
Reboot bool // Reboot system after adding package.
RebootAfter int // Reboot the system after "x" minutes.
Cleanup bool // Remove any pre-existing packages on the device.
RemoveAfter bool // Remove the package after successful installation.
}
// deployXML is XML we send (POST) for image deployment.
var deployXML = `
<exec-deploy>
<devices>
<device href= "/api/space/device-management/devices/%d"/>
</devices>
<deployOptions>
<useAlreadyDownloaded>%t</useAlreadyDownloaded>
<validate>%t</validate>
<bestEffortLoad>false</bestEffortLoad>
<snapShotRequired>false</snapShotRequired>
<rebootDevice>%t</rebootDevice>
<rebootAfterXMinutes>%d</rebootAfterXMinutes>
<cleanUpExistingOnDevice>%t</cleanUpExistingOnDevice>
<removePkgAfterInstallation>%t</removePkgAfterInstallation>
</deployOptions>
</exec-deploy>
`
// removeStagedXML is XML we send (POST) for removing a staged image.
var removeStagedXML = `
<exec-remove>
<devices>
<device href="/api/space/device-management/devices/%d"/>
</devices>
</exec-remove>
`
// stageXML is XML we send (POST) for staging an image on a device.
var stageXML = `
<exec-stage>
<devices>
<device href="/api/space/device-management/devices/%d"/>
</devices>
<stageOptions>
<cleanUpExistingOnDevice>%t</cleanUpExistingOnDevice>
</stageOptions>
</exec-stage>
`
// getSoftwareID returns the ID of the software package.
func (s *Space) getSoftwareID(image string) (int, error) {
var err error
var softwareID int
images, err := s.Software()
if err != nil {
return 0, err
}
for _, sw := range images.Packages {
if sw.Name == image {
softwareID = sw.ID
}
}
return softwareID, nil
}
// DeploySoftware starts the upgrade process on the device, using the given image along
// with the options specified.
func (s *Space) DeploySoftware(device, image string, options *SoftwareUpgrade) (int, error) {
r := rested.NewRequest()
r.BasicAuth(s.User, s.Password)
headers := map[string]string{
"Content-Type": contentExecDeploy,
}
var job jobID
deviceID, _ := s.getDeviceID(device)
softwareID, _ := s.getSoftwareID(image)
deploy := fmt.Sprintf(deployXML, deviceID, options.UseDownloaded, options.Validate, options.Reboot, options.RebootAfter, options.Cleanup, options.RemoveAfter)
uri := fmt.Sprintf("https://%s/api/space/software-management/packages/%d/exec-deploy", s.Host, softwareID)
resp := r.Send("post", uri, []byte(deploy), headers, nil)
if resp.Error != nil {
return 0, resp.Error
}
err := xml.Unmarshal(resp.Body, &job)
if err != nil {
return 0, err
}
return job.ID, nil
}
// RemoveStagedSoftware will delete the staged software image on the device.
func (s *Space) RemoveStagedSoftware(device, image string) (int, error) {
r := rested.NewRequest()
r.BasicAuth(s.User, s.Password)
headers := map[string]string{
"Content-Type": contentExecRemove,
}
var job jobID
deviceID, _ := s.getDeviceID(device)
softwareID, _ := s.getSoftwareID(image)
remove := fmt.Sprintf(removeStagedXML, deviceID)
uri := fmt.Sprintf("https://%s/api/space/software-management/packages/%d/exec-remove", s.Host, softwareID)
resp := r.Send("post", uri, []byte(remove), headers, nil)
if resp.Error != nil {
return 0, resp.Error
}
err := xml.Unmarshal(resp.Body, &job)
if err != nil {
return 0, err
}
return job.ID, nil
}
// Software queries the Junos Space server and returns all of the information
// about each software image that Space manages.
func (s *Space) Software() (*SoftwarePackages, error) {
r := rested.NewRequest()
r.BasicAuth(s.User, s.Password)
var software SoftwarePackages
uri := fmt.Sprintf("https://%s/api/space/software-management/packages", s.Host)
resp := r.Send("get", uri, nil, nil, nil)
if resp.Error != nil {
return nil, resp.Error
}
err := xml.Unmarshal(resp.Body, &software)
if err != nil {
return nil, err
}
return &software, nil
}
// StageSoftware loads the given software image onto the device but does not
// upgrade it. The package is placed in the /var/tmp directory.
func (s *Space) StageSoftware(device, image string, cleanup bool) (int, error) {
r := rested.NewRequest()
r.BasicAuth(s.User, s.Password)
headers := map[string]string{
"Content-Type": contentExecStage,
}
var job jobID
deviceID, _ := s.getDeviceID(device)
softwareID, _ := s.getSoftwareID(image)
stage := fmt.Sprintf(stageXML, deviceID, cleanup)
uri := fmt.Sprintf("https://%s/api/space/software-management/packages/%d/exec-stage", s.Host, softwareID)
resp := r.Send("post", uri, []byte(stage), headers, nil)
if resp.Error != nil {
return 0, resp.Error
}
err := xml.Unmarshal(resp.Body, &job)
if err != nil {
return 0, err
}
return job.ID, nil
}