Skip to content

Commit 1cb0dab

Browse files
authored
Merge pull request #471 from replicatedhq/divolgin/windows
Fix windows build
2 parents e7daba9 + db3d27d commit 1cb0dab

File tree

4 files changed

+366
-296
lines changed

4 files changed

+366
-296
lines changed

.github/workflows/build-test-deploy.yaml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,26 @@ jobs:
118118
- run: ./bin/support-bundle ./examples/support-bundle/sample-supportbundle.yaml
119119
- run: ./bin/support-bundle https://kots.io
120120

121+
goreleaser-test:
122+
runs-on: ubuntu-latest
123+
if: startsWith(github.ref, 'refs/tags/v') != true
124+
steps:
125+
- name: Checkout
126+
uses: actions/checkout@v2
127+
128+
- name: Unshallow
129+
run: git fetch --prune --unshallow
130+
131+
- uses: actions/setup-go@v1
132+
with:
133+
go-version: "1.17"
134+
135+
- name: Run GoReleaser
136+
uses: goreleaser/goreleaser-action@v2
137+
with:
138+
version: "v0.183.0"
139+
args: build --rm-dist --snapshot --config deploy/.goreleaser.yaml
140+
121141
goreleaser:
122142
runs-on: ubuntu-latest
123143
needs:
@@ -159,7 +179,7 @@ jobs:
159179
- name: Run GoReleaser
160180
uses: goreleaser/goreleaser-action@v2
161181
with:
162-
version: "v0.166.1"
182+
version: "v0.183.0"
163183
args: release --rm-dist --config deploy/.goreleaser.yaml
164184
env:
165185
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

pkg/longhorn/util/iscsi.go

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
// +build !windows
2+
3+
package util
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
"path/filepath"
9+
"strings"
10+
11+
"github.com/pkg/errors"
12+
"github.com/sirupsen/logrus"
13+
14+
iscsi_util "github.com/longhorn/go-iscsi-helper/util"
15+
)
16+
17+
func GetDiskInfo(directory string) (info *DiskInfo, err error) {
18+
defer func() {
19+
err = errors.Wrapf(err, "cannot get disk info of directory %v", directory)
20+
}()
21+
initiatorNSPath := iscsi_util.GetHostNamespacePath(HostProcPath)
22+
mountPath := fmt.Sprintf("--mount=%s/mnt", initiatorNSPath)
23+
output, err := Execute([]string{}, "nsenter", mountPath, "stat", "-fc", "{\"path\":\"%n\",\"fsid\":\"%i\",\"type\":\"%T\",\"freeBlock\":%f,\"totalBlock\":%b,\"blockSize\":%S}", directory)
24+
if err != nil {
25+
return nil, err
26+
}
27+
output = strings.Replace(output, "\n", "", -1)
28+
29+
diskInfo := &DiskInfo{}
30+
err = json.Unmarshal([]byte(output), diskInfo)
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
diskInfo.StorageMaximum = diskInfo.TotalBlock * diskInfo.BlockSize
36+
diskInfo.StorageAvailable = diskInfo.FreeBlock * diskInfo.BlockSize
37+
38+
return diskInfo, nil
39+
}
40+
41+
func RemoveHostDirectoryContent(directory string) (err error) {
42+
defer func() {
43+
err = errors.Wrapf(err, "failed to remove host directory %v", directory)
44+
}()
45+
46+
dir, err := filepath.Abs(filepath.Clean(directory))
47+
if err != nil {
48+
return err
49+
}
50+
if strings.Count(dir, "/") < 2 {
51+
return fmt.Errorf("prohibit removing the top level of directory %v", dir)
52+
}
53+
initiatorNSPath := iscsi_util.GetHostNamespacePath(HostProcPath)
54+
nsExec, err := iscsi_util.NewNamespaceExecutor(initiatorNSPath)
55+
if err != nil {
56+
return err
57+
}
58+
// check if the directory already deleted
59+
if _, err := nsExec.Execute("ls", []string{dir}); err != nil {
60+
logrus.Warnf("cannot find host directory %v for removal", dir)
61+
return nil
62+
}
63+
if _, err := nsExec.Execute("rm", []string{"-rf", dir}); err != nil {
64+
return err
65+
}
66+
return nil
67+
}
68+
69+
func CopyHostDirectoryContent(src, dest string) (err error) {
70+
defer func() {
71+
err = errors.Wrapf(err, "failed to copy the content from %v to %v for the host", src, dest)
72+
}()
73+
74+
srcDir, err := filepath.Abs(filepath.Clean(src))
75+
if err != nil {
76+
return err
77+
}
78+
destDir, err := filepath.Abs(filepath.Clean(dest))
79+
if err != nil {
80+
return err
81+
}
82+
if strings.Count(srcDir, "/") < 2 || strings.Count(destDir, "/") < 2 {
83+
return fmt.Errorf("prohibit copying the content for the top level of directory %v or %v", srcDir, destDir)
84+
}
85+
86+
initiatorNSPath := iscsi_util.GetHostNamespacePath(HostProcPath)
87+
nsExec, err := iscsi_util.NewNamespaceExecutor(initiatorNSPath)
88+
if err != nil {
89+
return err
90+
}
91+
92+
// There can be no src directory, hence returning nil is fine.
93+
if _, err := nsExec.Execute("bash", []string{"-c", fmt.Sprintf("ls %s", filepath.Join(srcDir, "*"))}); err != nil {
94+
logrus.Infof("cannot list the content of the src directory %v for the copy, will do nothing: %v", srcDir, err)
95+
return nil
96+
}
97+
// Check if the dest directory exists.
98+
if _, err := nsExec.Execute("mkdir", []string{"-p", destDir}); err != nil {
99+
return err
100+
}
101+
// The flag `-n` means not overwriting an existing file.
102+
if _, err := nsExec.Execute("bash", []string{"-c", fmt.Sprintf("cp -an %s %s", filepath.Join(srcDir, "*"), destDir)}); err != nil {
103+
return err
104+
}
105+
return nil
106+
}
107+
108+
func CreateDiskPathReplicaSubdirectory(path string) error {
109+
nsPath := iscsi_util.GetHostNamespacePath(HostProcPath)
110+
nsExec, err := iscsi_util.NewNamespaceExecutor(nsPath)
111+
if err != nil {
112+
return err
113+
}
114+
if _, err := nsExec.Execute("mkdir", []string{"-p", filepath.Join(path, ReplicaDirectory)}); err != nil {
115+
return errors.Wrapf(err, "error creating data path %v on host", path)
116+
}
117+
118+
return nil
119+
}
120+
121+
func DeleteDiskPathReplicaSubdirectoryAndDiskCfgFile(
122+
nsExec *iscsi_util.NamespaceExecutor, path string) error {
123+
124+
var err error
125+
dirPath := filepath.Join(path, ReplicaDirectory)
126+
filePath := filepath.Join(path, DiskConfigFile)
127+
128+
// Check if the replica directory exist, delete it
129+
if _, err := nsExec.Execute("ls", []string{dirPath}); err == nil {
130+
if _, err := nsExec.Execute("rmdir", []string{dirPath}); err != nil {
131+
return errors.Wrapf(err, "error deleting data path %v on host", path)
132+
}
133+
}
134+
135+
// Check if the disk cfg file exist, delete it
136+
if _, err := nsExec.Execute("ls", []string{filePath}); err == nil {
137+
if _, err := nsExec.Execute("rm", []string{filePath}); err != nil {
138+
err = errors.Wrapf(err, "error deleting disk cfg file %v on host", filePath)
139+
}
140+
}
141+
142+
return err
143+
}
144+
145+
func ExpandFileSystem(volumeName string) (err error) {
146+
devicePath := filepath.Join(DeviceDirectory, volumeName)
147+
nsPath := iscsi_util.GetHostNamespacePath(HostProcPath)
148+
nsExec, err := iscsi_util.NewNamespaceExecutor(nsPath)
149+
if err != nil {
150+
return err
151+
}
152+
153+
fsType, err := DetectFileSystem(volumeName)
154+
if err != nil {
155+
return err
156+
}
157+
if !IsSupportedFileSystem(fsType) {
158+
return fmt.Errorf("volume %v is using unsupported file system %v", volumeName, fsType)
159+
}
160+
161+
// make sure there is a mount point for the volume before file system expansion
162+
tmpMountNeeded := true
163+
mountPoint := ""
164+
mountRes, err := nsExec.Execute("bash", []string{"-c", "mount | grep \"/" + volumeName + " \" | awk '{print $3}'"})
165+
if err != nil {
166+
logrus.Warnf("failed to use command mount to get the mount info of volume %v, consider the volume as unmounted: %v", volumeName, err)
167+
} else {
168+
// For empty `mountRes`, `mountPoints` is [""]
169+
mountPoints := strings.Split(strings.TrimSpace(mountRes), "\n")
170+
if !(len(mountPoints) == 1 && strings.TrimSpace(mountPoints[0]) == "") {
171+
// pick up a random mount point
172+
for _, m := range mountPoints {
173+
mountPoint = strings.TrimSpace(m)
174+
if mountPoint != "" {
175+
tmpMountNeeded = false
176+
break
177+
}
178+
}
179+
if tmpMountNeeded {
180+
logrus.Errorf("BUG: Found mount point records %v for volume %v but there is no valid(non-empty) mount point", mountRes, volumeName)
181+
}
182+
}
183+
}
184+
if tmpMountNeeded {
185+
mountPoint = filepath.Join(TemporaryMountPointDirectory, volumeName)
186+
logrus.Infof("The volume %v is unmounted, hence it will be temporarily mounted on %v for file system expansion", volumeName, mountPoint)
187+
if _, err := nsExec.Execute("mkdir", []string{"-p", mountPoint}); err != nil {
188+
return errors.Wrapf(err, "failed to create a temporary mount point %v before file system expansion", mountPoint)
189+
}
190+
if _, err := nsExec.Execute("mount", []string{devicePath, mountPoint}); err != nil {
191+
return errors.Wrapf(err, "failed to temporarily mount volume %v on %v before file system expansion", volumeName, mountPoint)
192+
}
193+
}
194+
195+
switch fsType {
196+
case "ext2":
197+
fallthrough
198+
case "ext3":
199+
fallthrough
200+
case "ext4":
201+
if _, err = nsExec.Execute("resize2fs", []string{devicePath}); err != nil {
202+
return err
203+
}
204+
case "xfs":
205+
if _, err = nsExec.Execute("xfs_growfs", []string{mountPoint}); err != nil {
206+
return err
207+
}
208+
default:
209+
return fmt.Errorf("volume %v is using unsupported file system %v", volumeName, fsType)
210+
}
211+
212+
// cleanup
213+
if tmpMountNeeded {
214+
if _, err := nsExec.Execute("umount", []string{mountPoint}); err != nil {
215+
return errors.Wrapf(err, "failed to unmount volume %v on the temporary mount point %v after file system expansion", volumeName, mountPoint)
216+
}
217+
if _, err := nsExec.Execute("rm", []string{"-r", mountPoint}); err != nil {
218+
return errors.Wrapf(err, "failed to remove the temporary mount point %v after file system expansion", mountPoint)
219+
}
220+
}
221+
222+
return nil
223+
}
224+
225+
func DetectFileSystem(volumeName string) (string, error) {
226+
devicePath := filepath.Join(DeviceDirectory, volumeName)
227+
nsPath := iscsi_util.GetHostNamespacePath(HostProcPath)
228+
nsExec, err := iscsi_util.NewNamespaceExecutor(nsPath)
229+
if err != nil {
230+
return "", err
231+
}
232+
233+
// The output schema of `blkid` can be different.
234+
// For filesystem `btrfs`, the schema is: `<device path>: UUID="<filesystem UUID>" UUID_SUB="<filesystem UUID_SUB>" TYPE="<filesystem type>"`
235+
// For filesystem `ext4` or `xfs`, the schema is: `<device path>: UUID="<filesystem UUID>" TYPE="<filesystem type>"`
236+
cmd := fmt.Sprintf("blkid %s | sed 's/.*TYPE=//g'", devicePath)
237+
output, err := nsExec.Execute("bash", []string{"-c", cmd})
238+
if err != nil {
239+
return "", errors.Wrapf(err, "failed to get the file system info for volume %v, maybe there is no Linux file system on the volume", volumeName)
240+
}
241+
fsType := strings.Trim(strings.TrimSpace(output), "\"")
242+
if fsType == "" {
243+
return "", fmt.Errorf("cannot get the filesystem type by using the command %v", cmd)
244+
}
245+
return fsType, nil
246+
}
247+
248+
func GetDiskConfig(path string) (*DiskConfig, error) {
249+
nsPath := iscsi_util.GetHostNamespacePath(HostProcPath)
250+
nsExec, err := iscsi_util.NewNamespaceExecutor(nsPath)
251+
if err != nil {
252+
return nil, err
253+
}
254+
filePath := filepath.Join(path, DiskConfigFile)
255+
output, err := nsExec.Execute("cat", []string{filePath})
256+
if err != nil {
257+
return nil, fmt.Errorf("cannot find config file %v on host: %v", filePath, err)
258+
}
259+
260+
cfg := &DiskConfig{}
261+
if err := json.Unmarshal([]byte(output), cfg); err != nil {
262+
return nil, fmt.Errorf("failed to unmarshal %v content %v on host: %v", filePath, output, err)
263+
}
264+
return cfg, nil
265+
}
266+
267+
func GenerateDiskConfig(path string) (*DiskConfig, error) {
268+
cfg := &DiskConfig{
269+
DiskUUID: UUID(),
270+
}
271+
encoded, err := json.Marshal(cfg)
272+
if err != nil {
273+
return nil, fmt.Errorf("BUG: Cannot marshal %+v: %v", cfg, err)
274+
}
275+
276+
nsPath := iscsi_util.GetHostNamespacePath(HostProcPath)
277+
nsExec, err := iscsi_util.NewNamespaceExecutor(nsPath)
278+
if err != nil {
279+
return nil, err
280+
}
281+
filePath := filepath.Join(path, DiskConfigFile)
282+
if _, err := nsExec.Execute("ls", []string{filePath}); err == nil {
283+
return nil, fmt.Errorf("disk cfg on %v exists, cannot override", filePath)
284+
}
285+
286+
defer func() {
287+
if err != nil {
288+
if derr := DeleteDiskPathReplicaSubdirectoryAndDiskCfgFile(nsExec, path); derr != nil {
289+
err = errors.Wrapf(err, "cleaning up disk config path %v failed with error: %v", path, derr)
290+
}
291+
292+
}
293+
}()
294+
295+
if _, err := nsExec.ExecuteWithStdin("dd", []string{"of=" + filePath}, string(encoded)); err != nil {
296+
return nil, fmt.Errorf("cannot write to disk cfg on %v: %v", filePath, err)
297+
}
298+
if err := CreateDiskPathReplicaSubdirectory(path); err != nil {
299+
return nil, err
300+
}
301+
if _, err := nsExec.Execute("sync", []string{filePath}); err != nil {
302+
return nil, fmt.Errorf("cannot sync disk cfg on %v: %v", filePath, err)
303+
}
304+
305+
return cfg, nil
306+
}

pkg/longhorn/util/iscsi_windows.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// +build windows
2+
3+
package util
4+
5+
import (
6+
"github.com/pkg/errors"
7+
)
8+
9+
func GetDiskInfo(directory string) (*DiskInfo, error) {
10+
return nil, errors.Errorf("cannot get disk info of directory %v", directory)
11+
}
12+
13+
func RemoveHostDirectoryContent(directory string) error {
14+
return errors.Errorf("failed to remove host directory %v", directory)
15+
}
16+
17+
func CopyHostDirectoryContent(src, dest string) error {
18+
return errors.Errorf("failed to copy the content from %v to %v for the host", src, dest)
19+
}
20+
21+
func CreateDiskPathReplicaSubdirectory(path string) error {
22+
return errors.Errorf("error creating data path %v on host", path)
23+
}
24+
25+
func ExpandFileSystem(volumeName string) error {
26+
return errors.Errorf("error expanding filsystem on %v", volumeName)
27+
}
28+
29+
func DetectFileSystem(volumeName string) (string, error) {
30+
return "", errors.Errorf("error detecting filsystem on %v", volumeName)
31+
}
32+
33+
func GetDiskConfig(path string) (*DiskConfig, error) {
34+
return nil, errors.Errorf("error getting disk config from %v", path)
35+
}
36+
37+
func GenerateDiskConfig(path string) (*DiskConfig, error) {
38+
return nil, errors.Errorf("error generating disk config from %v", path)
39+
}

0 commit comments

Comments
 (0)