Skip to content

Commit e927123

Browse files
authored
fix(lvm): change calling operation to avoid garbage in json object (#250)
* fix(lvm): change calling operation to avoid garbage in json object Drop the STDERR stream contents from `output` to avoid JSON mangling. The `vgs` command may print non-critical warnings to STDERR. Warnings may not necessarily result in a failure return code, which allows the program to continue with marshalling the JSON-formatted output. Combining this stream with STDIN will cause the next step at `decodeVgsJSON()` to fail due to garbage mixed in the JSON. Fixes #247 Signed-off-by: Kara <[email protected]> * fix(lvm): add PR changelog - suppress STDERR when calling vgs Add PR changelog Signed-off-by: Kara <[email protected]> * refactor(lvm): refactor exec to separate function, add log verbosity Move exec code into separate function which returns STDOUT and STDERR streams separately. This is to facilitate future occurences of that same pattern within lvm_util.go . Additionally, add log messages to assist with debugging lvm and json. Signed-off-by: Kara <[email protected]> * feat(ci): integrate test to simulate foreign lvm systemid This test aims to determine whether lvm-driver is capable of operating with a volume group whose systemid is foreign to the kubernetes host system. The test ensures the program in pkg/lvm/lvm_utils.go is capable of operating in a foreign lvm environment. This is important when the kubernetes host system has a different lvm configuration than the lvm-driver container. Differences in configuration may cause unforseen consequences when the host machine provisions a volume group which is to be consumed by the lvm-driver container. Additionally, this feature includes teardown code in the form of the cleanup functions which aims to aid with cleaning up ci resources in a local development environment. To make the cleanup actions compatible with the original operation of the ci-test.sh script, the feature is only enabled through the use of environment variables. While this commit fixes issue #249, it's intent was as an integration test for issue #247. Fixes #249 Signed-off-by: Kara <[email protected]> * feat(ci): clean up volume groups when applicable To avoid volume group caching, explicitly remove volume groups (and their pvs) before removing the disk and loopback device. Signed-off-by: Kara <[email protected]> * fix(ci): use -n instead of ! -z, change last statement to return true Fix linter errors: use -n instead of ! -z in test statements. Last statement in file is used as the return code of the file, so it must return true; change `[ ! -z ... ] && ...` into `[ -z ... ] || ...` to achieve this. Signed-off-by: kro <[email protected]> --------- Signed-off-by: Kara <[email protected]> Signed-off-by: kro <[email protected]>
1 parent a8e8909 commit e927123

File tree

3 files changed

+114
-20
lines changed

3 files changed

+114
-20
lines changed

changelogs/unreleased/250-kro-cat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Drop the STDERR stream contents from output to avoid JSON mangling.
2+
3+
The vgs command may print non-critical warnings to STDERR. Warnings may not
4+
necessarily result in a failure return code, which allows the program to
5+
continue with marshalling the JSON-formatted output. Combining this stream with
6+
STDIN will cause the next step at decodeVgsJSON() to fail due to garbage mixed
7+
in the JSON.
8+

ci/ci-test.sh

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,91 @@
1616

1717
set -e
1818

19+
LVM_OPERATOR="$(realpath deploy/lvm-operator.yaml)"
20+
SNAP_CLASS="$(realpath deploy/sample/lvmsnapclass.yaml)"
21+
22+
export LVM_NAMESPACE="openebs"
23+
export TEST_DIR="tests"
24+
export NAMESPACE="kube-system"
25+
26+
# allow override
27+
if [ -z "${KUBECONFIG}" ]
28+
then
29+
export KUBECONFIG="${HOME}/.kube/config"
30+
fi
31+
32+
# systemid for the testing environment. The kubernetes host machine will serve as the foreign lvm system.
33+
LVM_SYSTEMID="openebs-ci-test-system"
34+
LVM_CONFIG="global{system_id_source=lvmlocal}local{system_id=${LVM_SYSTEMID}}"
35+
36+
# Clean up generated resources for successive tests.
37+
cleanup_loopdev() {
38+
sudo losetup -l | grep '(deleted)' | awk '{print $1}' \
39+
| while IFS= read -r disk
40+
do
41+
sudo losetup -d "${disk}"
42+
done
43+
}
44+
45+
cleanup_lvmvg() {
46+
if [ -f /tmp/openebs_ci_disk.img ]
47+
then
48+
sudo vgremove lvmvg -y || true
49+
rm /tmp/openebs_ci_disk.img
50+
fi
51+
cleanup_loopdev
52+
}
53+
54+
cleanup_foreign_lvmvg() {
55+
if [ -f /tmp/openebs_ci_foreign_disk.img ]
56+
then
57+
sudo vgremove foreign_lvmvg --config="${LVM_CONFIG}" -y || true
58+
rm /tmp/openebs_ci_foreign_disk.img
59+
fi
60+
cleanup_loopdev
61+
}
62+
63+
cleanup() {
64+
set +e
65+
66+
echo "Cleaning up test resources"
67+
68+
cleanup_lvmvg
69+
cleanup_foreign_lvmvg
70+
71+
kubectl delete pvc -n openebs lvmpv-pvc
72+
kubectl delete -f "${SNAP_CLASS}"
73+
kubectl delete -f "${LVM_OPERATOR}"
74+
75+
# always return true
76+
return 0
77+
}
78+
# trap "cleanup 2>/dev/null" EXIT
79+
[ -n "${CLEANUP_ONLY}" ] && cleanup 2>/dev/null && exit 0
80+
[ -n "${RESET}" ] && cleanup 2>/dev/null
81+
1982
# setup the lvm volume group to create the volume
20-
truncate -s 1024G /tmp/disk.img
21-
disk=`sudo losetup -f /tmp/disk.img --show`
22-
sudo pvcreate "$disk"
23-
sudo vgcreate lvmvg "$disk"
83+
cleanup_lvmvg
84+
truncate -s 1024G /tmp/openebs_ci_disk.img
85+
disk="$(sudo losetup -f /tmp/openebs_ci_disk.img --show)"
86+
sudo pvcreate "${disk}"
87+
sudo vgcreate lvmvg "${disk}"
88+
89+
# setup a foreign lvm to test
90+
cleanup_foreign_lvmvg
91+
truncate -s 1024G /tmp/openebs_ci_foreign_disk.img
92+
foreign_disk="$(sudo losetup -f /tmp/openebs_ci_foreign_disk.img --show)"
93+
sudo pvcreate "${foreign_disk}"
94+
sudo vgcreate foreign_lvmvg "${foreign_disk}" --systemid="${LVM_SYSTEMID}"
2495

2596
# install snapshot and thin volume module for lvm
2697
sudo modprobe dm-snapshot
2798
sudo modprobe dm_thin_pool
2899

29-
30-
LVM_OPERATOR=deploy/lvm-operator.yaml
31-
SNAP_CLASS=deploy/sample/lvmsnapclass.yaml
32-
33-
export LVM_NAMESPACE="openebs"
34-
export TEST_DIR="tests"
35-
export NAMESPACE="kube-system"
36-
export KUBECONFIG=$HOME/.kube/config
37-
38100
# Prepare env for running BDD tests
39101
# Minikube is already running
40-
kubectl apply -f $LVM_OPERATOR
41-
kubectl apply -f $SNAP_CLASS
102+
kubectl apply -f "${LVM_OPERATOR}"
103+
kubectl apply -f "${SNAP_CLASS}"
42104

43105
dumpAgentLogs() {
44106
NR=$1
@@ -99,9 +161,7 @@ set +e
99161

100162
echo "running ginkgo test case"
101163

102-
ginkgo -v
103-
104-
if [ $? -ne 0 ]; then
164+
if ! ginkgo -v ; then
105165

106166
sudo pvscan --cache
107167

@@ -135,3 +195,6 @@ exit 1
135195
fi
136196

137197
printf "\n\n######### All test cases passed #########\n\n"
198+
199+
# last statement formatted to always return true
200+
[ -z "${CLEANUP}" ] || cleanup 2>/dev/null

pkg/lvm/lvm_util.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package lvm
1818

1919
import (
20+
"bytes"
2021
"encoding/json"
2122
"fmt"
2223
"os"
@@ -550,6 +551,7 @@ func decodeVgsJSON(raw []byte) ([]apis.VolumeGroup, error) {
550551
}{}
551552
var err error
552553
if err = json.Unmarshal(raw, output); err != nil {
554+
klog.Errorf("json: failed to unmarshal:\n%s", raw)
553555
return nil, err
554556
}
555557

@@ -646,6 +648,27 @@ func ReloadLVMMetadataCache() error {
646648
return nil
647649
}
648650

651+
// RunCommandSplit is a wrapper function to run a command and receive its
652+
// STDERR and STDOUT streams in separate []byte vars.
653+
func RunCommandSplit(command string, args ...string) ([]byte, []byte, error) {
654+
var cmdStdout bytes.Buffer
655+
var cmdStderr bytes.Buffer
656+
657+
cmd := exec.Command(command, args...)
658+
cmd.Stdout = &cmdStdout
659+
cmd.Stderr = &cmdStderr
660+
err := cmd.Run()
661+
662+
output := cmdStdout.Bytes()
663+
error_output := cmdStderr.Bytes()
664+
665+
if len(error_output) > 0 {
666+
klog.Warningf("lvm: said into stderr: %s", error_output)
667+
}
668+
669+
return output, error_output, err
670+
}
671+
649672
// ListLVMVolumeGroup invokes `vgs` to list all the available volume
650673
// groups in the node.
651674
//
@@ -662,12 +685,12 @@ func ListLVMVolumeGroup(reloadCache bool) ([]apis.VolumeGroup, error) {
662685
"--reportformat", "json",
663686
"--units", "b",
664687
}
665-
cmd := exec.Command(VGList, args...)
666-
output, err := cmd.CombinedOutput()
688+
output, _, err := RunCommandSplit(VGList, args...)
667689
if err != nil {
668690
klog.Errorf("lvm: list volume group cmd %v: %v", args, err)
669691
return nil, err
670692
}
693+
671694
return decodeVgsJSON(output)
672695
}
673696

0 commit comments

Comments
 (0)