Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
234f3ed8
Commit
234f3ed8
authored
Jul 19, 2015
by
saadali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make GCE PD attach block on pending detach. Retry on detach/attach errors.
parent
dfe1eb9b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
345 additions
and
194 deletions
+345
-194
operationmanager.go
pkg/util/operationmanager/operationmanager.go
+11
-0
operationmanager_test.go
pkg/util/operationmanager/operationmanager_test.go
+72
-52
gce_util.go
pkg/volume/gce_pd/gce_util.go
+104
-69
framework.go
test/e2e/framework.go
+49
-0
pd.go
test/e2e/pd.go
+109
-73
No files found.
pkg/util/operationmanager/operationmanager.go
View file @
234f3ed8
...
@@ -37,6 +37,9 @@ type OperationManager interface {
...
@@ -37,6 +37,9 @@ type OperationManager interface {
// Attempts to send msg to the channel associated with ID.
// Attempts to send msg to the channel associated with ID.
// Returns an error if no associated channel exists.
// Returns an error if no associated channel exists.
Send
(
id
string
,
msg
interface
{})
error
Send
(
id
string
,
msg
interface
{})
error
// Returns true if an entry with the specified ID already exists.
Exists
(
id
string
)
bool
}
}
// Returns a new instance of a channel manager.
// Returns a new instance of a channel manager.
...
@@ -90,3 +93,11 @@ func (cm *operationManager) Send(id string, msg interface{}) error {
...
@@ -90,3 +93,11 @@ func (cm *operationManager) Send(id string, msg interface{}) error {
cm
.
chanMap
[
id
]
<-
msg
cm
.
chanMap
[
id
]
<-
msg
return
nil
return
nil
}
}
// Returns true if an entry with the specified ID already exists.
func
(
cm
*
operationManager
)
Exists
(
id
string
)
(
exists
bool
)
{
cm
.
RLock
()
defer
cm
.
RUnlock
()
_
,
exists
=
cm
.
chanMap
[
id
]
return
}
pkg/util/operationmanager/operationmanager_test.go
View file @
234f3ed8
...
@@ -32,15 +32,10 @@ func TestStart(t *testing.T) {
...
@@ -32,15 +32,10 @@ func TestStart(t *testing.T) {
sigErr
:=
cm
.
Send
(
chanId
,
testMsg
)
sigErr
:=
cm
.
Send
(
chanId
,
testMsg
)
// Assert
// Assert
if
startErr
!=
nil
{
verifyNoError
(
t
,
startErr
,
"Start"
)
t
.
Fatalf
(
"Unexpected error on Start. Expected: <no error> Actual: <%v>"
,
startErr
)
verifyNoError
(
t
,
sigErr
,
"Send"
)
}
actualMsg
:=
<-
ch
if
sigErr
!=
nil
{
verifyMsg
(
t
,
testMsg
/* expected */
,
actualMsg
.
(
string
)
/* actual */
)
t
.
Fatalf
(
"Unexpected error on Send. Expected: <no error> Actual: <%v>"
,
sigErr
)
}
if
actual
:=
<-
ch
;
actual
!=
testMsg
{
t
.
Fatalf
(
"Unexpected testMsg value. Expected: <%v> Actual: <%v>"
,
testMsg
,
actual
)
}
}
}
func
TestStartIdExists
(
t
*
testing
.
T
)
{
func
TestStartIdExists
(
t
*
testing
.
T
)
{
...
@@ -53,12 +48,8 @@ func TestStartIdExists(t *testing.T) {
...
@@ -53,12 +48,8 @@ func TestStartIdExists(t *testing.T) {
_
,
startErr2
:=
cm
.
Start
(
chanId
,
1
/* bufferSize */
)
_
,
startErr2
:=
cm
.
Start
(
chanId
,
1
/* bufferSize */
)
// Assert
// Assert
if
startErr1
!=
nil
{
verifyNoError
(
t
,
startErr1
,
"Start1"
)
t
.
Fatalf
(
"Unexpected error on Start1. Expected: <no error> Actual: <%v>"
,
startErr1
)
verifyError
(
t
,
startErr2
,
"Start2"
)
}
if
startErr2
==
nil
{
t
.
Fatalf
(
"Expected error on Start2. Expected: <id already exists error> Actual: <no error>"
)
}
}
}
func
TestStartAndAdd2Chans
(
t
*
testing
.
T
)
{
func
TestStartAndAdd2Chans
(
t
*
testing
.
T
)
{
...
@@ -76,25 +67,14 @@ func TestStartAndAdd2Chans(t *testing.T) {
...
@@ -76,25 +67,14 @@ func TestStartAndAdd2Chans(t *testing.T) {
sigErr2
:=
cm
.
Send
(
chanId2
,
testMsg2
)
sigErr2
:=
cm
.
Send
(
chanId2
,
testMsg2
)
// Assert
// Assert
if
startErr1
!=
nil
{
verifyNoError
(
t
,
startErr1
,
"Start1"
)
t
.
Fatalf
(
"Unexpected error on Start1. Expected: <no error> Actual: <%v>"
,
startErr1
)
verifyNoError
(
t
,
startErr2
,
"Start2"
)
}
verifyNoError
(
t
,
sigErr1
,
"Send1"
)
if
startErr2
!=
nil
{
verifyNoError
(
t
,
sigErr2
,
"Send2"
)
t
.
Fatalf
(
"Unexpected error on Start2. Expected: <no error> Actual: <%v>"
,
startErr2
)
actualMsg1
:=
<-
ch1
}
actualMsg2
:=
<-
ch2
if
sigErr1
!=
nil
{
verifyMsg
(
t
,
testMsg1
/* expected */
,
actualMsg1
.
(
string
)
/* actual */
)
t
.
Fatalf
(
"Unexpected error on Send1. Expected: <no error> Actual: <%v>"
,
sigErr1
)
verifyMsg
(
t
,
testMsg2
/* expected */
,
actualMsg2
.
(
string
)
/* actual */
)
}
if
sigErr2
!=
nil
{
t
.
Fatalf
(
"Unexpected error on Send2. Expected: <no error> Actual: <%v>"
,
sigErr2
)
}
if
actual
:=
<-
ch1
;
actual
!=
testMsg1
{
t
.
Fatalf
(
"Unexpected testMsg value. Expected: <%v> Actual: <%v>"
,
testMsg1
,
actual
)
}
if
actual
:=
<-
ch2
;
actual
!=
testMsg2
{
t
.
Fatalf
(
"Unexpected testMsg value. Expected: <%v> Actual: <%v>"
,
testMsg2
,
actual
)
}
}
}
func
TestStartAndAdd2ChansAndClose
(
t
*
testing
.
T
)
{
func
TestStartAndAdd2ChansAndClose
(
t
*
testing
.
T
)
{
...
@@ -114,26 +94,66 @@ func TestStartAndAdd2ChansAndClose(t *testing.T) {
...
@@ -114,26 +94,66 @@ func TestStartAndAdd2ChansAndClose(t *testing.T) {
sigErr3
:=
cm
.
Send
(
chanId1
,
testMsg1
)
sigErr3
:=
cm
.
Send
(
chanId1
,
testMsg1
)
// Assert
// Assert
if
startErr1
!=
nil
{
verifyNoError
(
t
,
startErr1
,
"Start1"
)
t
.
Fatalf
(
"Unexpected error on Start1. Expected: <no error> Actual: <%v>"
,
startErr1
)
verifyNoError
(
t
,
startErr2
,
"Start2"
)
}
verifyNoError
(
t
,
sigErr1
,
"Send1"
)
if
startErr2
!=
nil
{
verifyNoError
(
t
,
sigErr2
,
"Send2"
)
t
.
Fatalf
(
"Unexpected error on Start2. Expected: <no error> Actual: <%v>"
,
startErr2
)
verifyError
(
t
,
sigErr3
,
"Send3"
)
}
actualMsg1
:=
<-
ch1
if
sigErr1
!=
nil
{
actualMsg2
:=
<-
ch2
t
.
Fatalf
(
"Unexpected error on Send1. Expected: <no error> Actual: <%v>"
,
sigErr1
)
verifyMsg
(
t
,
testMsg1
/* expected */
,
actualMsg1
.
(
string
)
/* actual */
)
}
verifyMsg
(
t
,
testMsg2
/* expected */
,
actualMsg2
.
(
string
)
/* actual */
)
if
sigErr2
!=
nil
{
}
t
.
Fatalf
(
"Unexpected error on Send2. Expected: <no error> Actual: <%v>"
,
sigErr2
)
}
func
TestExists
(
t
*
testing
.
T
)
{
if
sigErr3
==
nil
{
// Arrange
t
.
Fatalf
(
"Expected error on Send3. Expected: <error> Actual: <no error>"
,
sigErr2
)
cm
:=
NewOperationManager
()
chanId1
:=
"testChanId1"
chanId2
:=
"testChanId2"
// Act & Assert
verifyExists
(
t
,
cm
,
chanId1
,
false
/* expected */
)
verifyExists
(
t
,
cm
,
chanId2
,
false
/* expected */
)
_
,
startErr1
:=
cm
.
Start
(
chanId1
,
1
/* bufferSize */
)
verifyNoError
(
t
,
startErr1
,
"Start1"
)
verifyExists
(
t
,
cm
,
chanId1
,
true
/* expected */
)
verifyExists
(
t
,
cm
,
chanId2
,
false
/* expected */
)
_
,
startErr2
:=
cm
.
Start
(
chanId2
,
1
/* bufferSize */
)
verifyNoError
(
t
,
startErr2
,
"Start2"
)
verifyExists
(
t
,
cm
,
chanId1
,
true
/* expected */
)
verifyExists
(
t
,
cm
,
chanId2
,
true
/* expected */
)
cm
.
Close
(
chanId1
)
verifyExists
(
t
,
cm
,
chanId1
,
false
/* expected */
)
verifyExists
(
t
,
cm
,
chanId2
,
true
/* expected */
)
cm
.
Close
(
chanId2
)
verifyExists
(
t
,
cm
,
chanId1
,
false
/* expected */
)
verifyExists
(
t
,
cm
,
chanId2
,
false
/* expected */
)
}
func
verifyExists
(
t
*
testing
.
T
,
cm
OperationManager
,
id
string
,
expected
bool
)
{
if
actual
:=
cm
.
Exists
(
id
);
expected
!=
actual
{
t
.
Fatalf
(
"Unexpected Exists(%q) response. Expected: <%v> Actual: <%v>"
,
id
,
expected
,
actual
)
}
}
if
actual
:=
<-
ch1
;
actual
!=
testMsg1
{
}
t
.
Fatalf
(
"Unexpected testMsg value. Expected: <%v> Actual: <%v>"
,
testMsg1
,
actual
)
func
verifyNoError
(
t
*
testing
.
T
,
err
error
,
name
string
)
{
if
err
!=
nil
{
t
.
Fatalf
(
"Unexpected response on %q. Expected: <no error> Actual: <%v>"
,
name
,
err
)
}
}
if
actual
:=
<-
ch2
;
actual
!=
testMsg2
{
}
t
.
Fatalf
(
"Unexpected testMsg value. Expected: <%v> Actual: <%v>"
,
testMsg2
,
actual
)
func
verifyError
(
t
*
testing
.
T
,
err
error
,
name
string
)
{
if
err
==
nil
{
t
.
Fatalf
(
"Unexpected response on %q. Expected: <error> Actual: <no error>"
)
}
}
}
func
verifyMsg
(
t
*
testing
.
T
,
expected
,
actual
string
)
{
if
actual
!=
expected
{
t
.
Fatalf
(
"Unexpected testMsg value. Expected: <%v> Actual: <%v>"
,
expected
,
actual
)
}
}
}
pkg/volume/gce_pd/gce_util.go
View file @
234f3ed8
This diff is collapsed.
Click to expand it.
test/e2e/framework.go
View file @
234f3ed8
...
@@ -17,7 +17,9 @@ limitations under the License.
...
@@ -17,7 +17,9 @@ limitations under the License.
package
e2e
package
e2e
import
(
import
(
"bytes"
"fmt"
"fmt"
"strings"
"time"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
...
@@ -155,3 +157,50 @@ func (f *Framework) WaitForAnEndpoint(serviceName string) error {
...
@@ -155,3 +157,50 @@ func (f *Framework) WaitForAnEndpoint(serviceName string) error {
}
}
}
}
}
}
// Write a file using kubectl exec echo <contents> > <path> via specified container
// Because of the primitive technique we're using here, we only allow ASCII alphanumeric characters
func
(
f
*
Framework
)
WriteFileViaContainer
(
podName
,
containerName
string
,
path
string
,
contents
string
)
error
{
By
(
"writing a file in the container"
)
allowedCharacters
:=
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
for
_
,
c
:=
range
contents
{
if
!
strings
.
ContainsRune
(
allowedCharacters
,
c
)
{
return
fmt
.
Errorf
(
"Unsupported character in string to write: %v"
,
c
)
}
}
command
:=
fmt
.
Sprintf
(
"echo '%s' > '%s'"
,
contents
,
path
)
stdout
,
stderr
,
err
:=
kubectlExec
(
f
.
Namespace
.
Name
,
podName
,
containerName
,
"--"
,
"/bin/sh"
,
"-c"
,
command
)
if
err
!=
nil
{
Logf
(
"error running kubectl exec to write file: %v
\n
stdout=%v
\n
stderr=%v)"
,
err
,
string
(
stdout
),
string
(
stderr
))
}
return
err
}
// Read a file using kubectl exec cat <path>
func
(
f
*
Framework
)
ReadFileViaContainer
(
podName
,
containerName
string
,
path
string
)
(
string
,
error
)
{
By
(
"reading a file in the container"
)
stdout
,
stderr
,
err
:=
kubectlExec
(
f
.
Namespace
.
Name
,
podName
,
containerName
,
"--"
,
"cat"
,
path
)
if
err
!=
nil
{
Logf
(
"error running kubectl exec to read file: %v
\n
stdout=%v
\n
stderr=%v)"
,
err
,
string
(
stdout
),
string
(
stderr
))
}
return
string
(
stdout
),
err
}
func
kubectlExec
(
namespace
string
,
podName
,
containerName
string
,
args
...
string
)
([]
byte
,
[]
byte
,
error
)
{
var
stdout
,
stderr
bytes
.
Buffer
cmdArgs
:=
[]
string
{
"exec"
,
fmt
.
Sprintf
(
"--namespace=%v"
,
namespace
),
podName
,
fmt
.
Sprintf
(
"-c=%v"
,
containerName
),
}
cmdArgs
=
append
(
cmdArgs
,
args
...
)
cmd
:=
kubectlCmd
(
cmdArgs
...
)
cmd
.
Stdout
,
cmd
.
Stderr
=
&
stdout
,
&
stderr
Logf
(
"Running '%s %s'"
,
cmd
.
Path
,
strings
.
Join
(
cmd
.
Args
,
" "
))
err
:=
cmd
.
Run
()
return
stdout
.
Bytes
(),
stderr
.
Bytes
(),
err
}
test/e2e/pd.go
View file @
234f3ed8
...
@@ -23,9 +23,9 @@ import (
...
@@ -23,9 +23,9 @@ import (
"strings"
"strings"
"time"
"time"
"bytes"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/aws"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/aws"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
...
@@ -55,6 +55,8 @@ var _ = Describe("Pod Disks", func() {
...
@@ -55,6 +55,8 @@ var _ = Describe("Pod Disks", func() {
host0Name
=
nodes
.
Items
[
0
]
.
ObjectMeta
.
Name
host0Name
=
nodes
.
Items
[
0
]
.
ObjectMeta
.
Name
host1Name
=
nodes
.
Items
[
1
]
.
ObjectMeta
.
Name
host1Name
=
nodes
.
Items
[
1
]
.
ObjectMeta
.
Name
math_rand
.
Seed
(
time
.
Now
()
.
UTC
()
.
UnixNano
())
})
})
It
(
"should schedule a pod w/ a RW PD, remove it, then schedule it on another host"
,
func
()
{
It
(
"should schedule a pod w/ a RW PD, remove it, then schedule it on another host"
,
func
()
{
...
@@ -64,8 +66,8 @@ var _ = Describe("Pod Disks", func() {
...
@@ -64,8 +66,8 @@ var _ = Describe("Pod Disks", func() {
diskName
,
err
:=
createPD
()
diskName
,
err
:=
createPD
()
expectNoError
(
err
,
"Error creating PD"
)
expectNoError
(
err
,
"Error creating PD"
)
host0Pod
:=
testPDPod
(
diskName
,
host0Name
,
false
)
host0Pod
:=
testPDPod
(
diskName
,
host0Name
,
false
/* readOnly */
,
1
/* numContainers */
)
host1Pod
:=
testPDPod
(
diskName
,
host1Name
,
false
)
host1Pod
:=
testPDPod
(
diskName
,
host1Name
,
false
/* readOnly */
,
1
/* numContainers */
)
defer
func
()
{
defer
func
()
{
By
(
"cleaning up PD-RW test environment"
)
By
(
"cleaning up PD-RW test environment"
)
...
@@ -87,7 +89,7 @@ var _ = Describe("Pod Disks", func() {
...
@@ -87,7 +89,7 @@ var _ = Describe("Pod Disks", func() {
testFile
:=
"/testpd/tracker"
testFile
:=
"/testpd/tracker"
testFileContents
:=
fmt
.
Sprintf
(
"%v"
,
math_rand
.
Int
())
testFileContents
:=
fmt
.
Sprintf
(
"%v"
,
math_rand
.
Int
())
expectNoError
(
writeFileOnPod
(
framework
.
Client
,
host0Pod
.
Name
,
testFile
,
testFileContents
))
expectNoError
(
framework
.
WriteFileViaContainer
(
host0Pod
.
Name
,
"testpd"
/* containerName */
,
testFile
,
testFileContents
))
Logf
(
"Wrote value: %v"
,
testFileContents
)
Logf
(
"Wrote value: %v"
,
testFileContents
)
By
(
"deleting host0Pod"
)
By
(
"deleting host0Pod"
)
...
@@ -99,7 +101,7 @@ var _ = Describe("Pod Disks", func() {
...
@@ -99,7 +101,7 @@ var _ = Describe("Pod Disks", func() {
expectNoError
(
framework
.
WaitForPodRunning
(
host1Pod
.
Name
))
expectNoError
(
framework
.
WaitForPodRunning
(
host1Pod
.
Name
))
v
,
err
:=
readFileOnPod
(
framework
.
Client
,
host1Pod
.
Name
,
testFile
)
v
,
err
:=
framework
.
ReadFileViaContainer
(
host1Pod
.
Name
,
"testpd"
,
testFile
)
expectNoError
(
err
)
expectNoError
(
err
)
Logf
(
"Read value: %v"
,
v
)
Logf
(
"Read value: %v"
,
v
)
...
@@ -109,15 +111,7 @@ var _ = Describe("Pod Disks", func() {
...
@@ -109,15 +111,7 @@ var _ = Describe("Pod Disks", func() {
expectNoError
(
podClient
.
Delete
(
host1Pod
.
Name
,
nil
),
"Failed to delete host1Pod"
)
expectNoError
(
podClient
.
Delete
(
host1Pod
.
Name
,
nil
),
"Failed to delete host1Pod"
)
By
(
fmt
.
Sprintf
(
"deleting PD %q"
,
diskName
))
By
(
fmt
.
Sprintf
(
"deleting PD %q"
,
diskName
))
for
start
:=
time
.
Now
();
time
.
Since
(
start
)
<
180
*
time
.
Second
;
time
.
Sleep
(
5
*
time
.
Second
)
{
deletePDWithRetry
(
diskName
)
if
err
=
deletePD
(
diskName
);
err
!=
nil
{
Logf
(
"Couldn't delete PD. Sleeping 5 seconds (%v)"
,
err
)
continue
}
Logf
(
"Deleted PD %v"
,
diskName
)
break
}
expectNoError
(
err
,
"Error deleting PD"
)
return
return
})
})
...
@@ -129,9 +123,9 @@ var _ = Describe("Pod Disks", func() {
...
@@ -129,9 +123,9 @@ var _ = Describe("Pod Disks", func() {
diskName
,
err
:=
createPD
()
diskName
,
err
:=
createPD
()
expectNoError
(
err
,
"Error creating PD"
)
expectNoError
(
err
,
"Error creating PD"
)
rwPod
:=
testPDPod
(
diskName
,
host0Name
,
false
)
rwPod
:=
testPDPod
(
diskName
,
host0Name
,
false
/* readOnly */
,
1
/* numContainers */
)
host0ROPod
:=
testPDPod
(
diskName
,
host0Name
,
true
)
host0ROPod
:=
testPDPod
(
diskName
,
host0Name
,
true
/* readOnly */
,
1
/* numContainers */
)
host1ROPod
:=
testPDPod
(
diskName
,
host1Name
,
true
)
host1ROPod
:=
testPDPod
(
diskName
,
host1Name
,
true
/* readOnly */
,
1
/* numContainers */
)
defer
func
()
{
defer
func
()
{
By
(
"cleaning up PD-RO test environment"
)
By
(
"cleaning up PD-RO test environment"
)
...
@@ -171,58 +165,89 @@ var _ = Describe("Pod Disks", func() {
...
@@ -171,58 +165,89 @@ var _ = Describe("Pod Disks", func() {
expectNoError
(
podClient
.
Delete
(
host1ROPod
.
Name
,
nil
),
"Failed to delete host1ROPod"
)
expectNoError
(
podClient
.
Delete
(
host1ROPod
.
Name
,
nil
),
"Failed to delete host1ROPod"
)
By
(
fmt
.
Sprintf
(
"deleting PD %q"
,
diskName
))
By
(
fmt
.
Sprintf
(
"deleting PD %q"
,
diskName
))
for
start
:=
time
.
Now
();
time
.
Since
(
start
)
<
180
*
time
.
Second
;
time
.
Sleep
(
5
*
time
.
Second
)
{
deletePDWithRetry
(
diskName
)
if
err
=
deletePD
(
diskName
);
err
!=
nil
{
Logf
(
"Couldn't delete PD. Sleeping 5 seconds"
)
continue
}
Logf
(
"Successfully deleted PD %q"
,
diskName
)
break
}
expectNoError
(
err
,
"Error deleting PD"
)
expectNoError
(
err
,
"Error deleting PD"
)
})
})
})
func
kubectlExec
(
namespace
string
,
podName
string
,
args
...
string
)
([]
byte
,
[]
byte
,
error
)
{
It
(
"should schedule a pod w/ a RW PD shared between multiple containers, write to PD, delete pod, verify contents, and repeat in rapid succession"
,
func
()
{
var
stdout
,
stderr
bytes
.
Buffer
SkipUnlessProviderIs
(
"gce"
,
"gke"
,
"aws"
)
cmdArgs
:=
[]
string
{
"exec"
,
fmt
.
Sprintf
(
"--namespace=%v"
,
namespace
),
podName
}
cmdArgs
=
append
(
cmdArgs
,
args
...
)
By
(
"creating PD"
)
diskName
,
err
:=
createPD
()
expectNoError
(
err
,
"Error creating PD"
)
numContainers
:=
4
cmd
:=
kubectlCmd
(
cmdArgs
...
)
host0Pod
:=
testPDPod
(
diskName
,
host0Name
,
false
/* readOnly */
,
numContainers
)
cmd
.
Stdout
,
cmd
.
Stderr
=
&
stdout
,
&
stderr
Logf
(
"Running '%s %s'"
,
cmd
.
Path
,
strings
.
Join
(
cmd
.
Args
,
" "
))
defer
func
()
{
err
:=
cmd
.
Run
()
By
(
"cleaning up PD-RW test environment"
)
return
stdout
.
Bytes
(),
stderr
.
Bytes
(),
err
// Teardown pods, PD. Ignore errors.
}
// Teardown should do nothing unless test failed.
podClient
.
Delete
(
host0Pod
.
Name
,
nil
)
detachPD
(
host0Name
,
diskName
)
deletePD
(
diskName
)
}()
// Write a file using kubectl exec echo <contents> > <path>
fileAndContentToVerify
:=
make
(
map
[
string
]
string
)
// Because of the primitive technique we're using here, we only allow ASCII alphanumeric characters
for
i
:=
0
;
i
<
3
;
i
++
{
func
writeFileOnPod
(
c
*
client
.
Client
,
podName
string
,
path
string
,
contents
string
)
error
{
Logf
(
"PD Read/Writer Iteration #%v"
,
i
)
By
(
"writing a file in the container"
)
By
(
"submitting host0Pod to kubernetes"
)
allowedCharacters
:=
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
_
,
err
=
podClient
.
Create
(
host0Pod
)
for
_
,
c
:=
range
contents
{
expectNoError
(
err
,
fmt
.
Sprintf
(
"Failed to create host0Pod: %v"
,
err
))
if
!
strings
.
ContainsRune
(
allowedCharacters
,
c
)
{
return
fmt
.
Errorf
(
"Unsupported character in string to write: %v"
,
c
)
expectNoError
(
framework
.
WaitForPodRunning
(
host0Pod
.
Name
))
// randomly select a container and read/verify pd contents from it
containerName
:=
fmt
.
Sprintf
(
"testpd%v"
,
math_rand
.
Intn
(
numContainers
)
+
1
)
verifyPDContentsViaContainer
(
framework
,
host0Pod
.
Name
,
containerName
,
fileAndContentToVerify
)
// Randomly select a container to write a file to PD from
containerName
=
fmt
.
Sprintf
(
"testpd%v"
,
math_rand
.
Intn
(
numContainers
)
+
1
)
testFile
:=
fmt
.
Sprintf
(
"/testpd/tracker%v"
,
i
)
testFileContents
:=
fmt
.
Sprintf
(
"%v"
,
math_rand
.
Int
())
fileAndContentToVerify
[
testFile
]
=
testFileContents
expectNoError
(
framework
.
WriteFileViaContainer
(
host0Pod
.
Name
,
containerName
,
testFile
,
testFileContents
))
Logf
(
"Wrote value:
\"
%v
\"
to PD %q from pod %q container %q"
,
testFileContents
,
diskName
,
host0Pod
.
Name
,
containerName
)
// Randomly select a container and read/verify pd contents from it
containerName
=
fmt
.
Sprintf
(
"testpd%v"
,
math_rand
.
Intn
(
numContainers
)
+
1
)
verifyPDContentsViaContainer
(
framework
,
host0Pod
.
Name
,
containerName
,
fileAndContentToVerify
)
By
(
"deleting host0Pod"
)
expectNoError
(
podClient
.
Delete
(
host0Pod
.
Name
,
nil
),
"Failed to delete host0Pod"
)
}
}
By
(
fmt
.
Sprintf
(
"deleting PD %q"
,
diskName
))
deletePDWithRetry
(
diskName
)
return
})
})
func
deletePDWithRetry
(
diskName
string
)
{
var
err
error
for
start
:=
time
.
Now
();
time
.
Since
(
start
)
<
180
*
time
.
Second
;
time
.
Sleep
(
5
*
time
.
Second
)
{
if
err
=
deletePD
(
diskName
);
err
!=
nil
{
Logf
(
"Couldn't delete PD %q. Sleeping 5 seconds (%v)"
,
diskName
,
err
)
continue
}
Logf
(
"Deleted PD %v"
,
diskName
)
break
}
}
command
:=
fmt
.
Sprintf
(
"echo '%s' > '%s'"
,
contents
,
path
)
expectNoError
(
err
,
"Error deleting PD"
)
stdout
,
stderr
,
err
:=
kubectlExec
(
api
.
NamespaceDefault
,
podName
,
"--"
,
"/bin/sh"
,
"-c"
,
command
)
if
err
!=
nil
{
Logf
(
"error running kubectl exec to write file: %v
\n
stdout=%v
\n
stderr=%v)"
,
err
,
string
(
stdout
),
string
(
stderr
))
}
return
err
}
}
// Read a file using kubectl exec cat <path>
func
verifyPDContentsViaContainer
(
f
*
Framework
,
podName
,
containerName
string
,
fileAndContentToVerify
map
[
string
]
string
)
{
func
readFileOnPod
(
c
*
client
.
Client
,
podName
string
,
path
string
)
(
string
,
error
)
{
for
filePath
,
expectedContents
:=
range
fileAndContentToVerify
{
By
(
"reading a file in the container"
)
v
,
err
:=
f
.
ReadFileViaContainer
(
podName
,
containerName
,
filePath
)
if
err
!=
nil
{
stdout
,
stderr
,
err
:=
kubectlExec
(
api
.
NamespaceDefault
,
podName
,
"--"
,
"cat"
,
path
)
Logf
(
"Error reading file: %v"
,
err
)
if
err
!=
nil
{
}
Logf
(
"error running kubectl exec to read file: %v
\n
stdout=%v
\n
stderr=%v)"
,
err
,
string
(
stdout
),
string
(
stderr
))
expectNoError
(
err
)
Logf
(
"Read file %q with content: %v"
,
filePath
,
v
)
Expect
(
strings
.
TrimSpace
(
v
))
.
To
(
Equal
(
strings
.
TrimSpace
(
expectedContents
)))
}
}
return
string
(
stdout
),
err
}
}
func
createPD
()
(
string
,
error
)
{
func
createPD
()
(
string
,
error
)
{
...
@@ -284,7 +309,30 @@ func detachPD(hostName, pdName string) error {
...
@@ -284,7 +309,30 @@ func detachPD(hostName, pdName string) error {
}
}
}
}
func
testPDPod
(
diskName
,
targetHost
string
,
readOnly
bool
)
*
api
.
Pod
{
func
testPDPod
(
diskName
,
targetHost
string
,
readOnly
bool
,
numContainers
int
)
*
api
.
Pod
{
containers
:=
make
([]
api
.
Container
,
numContainers
)
for
i
:=
range
containers
{
containers
[
i
]
.
Name
=
"testpd"
if
numContainers
>
1
{
containers
[
i
]
.
Name
=
fmt
.
Sprintf
(
"testpd%v"
,
i
+
1
)
}
containers
[
i
]
.
Image
=
"gcr.io/google_containers/busybox"
containers
[
i
]
.
Command
=
[]
string
{
"sleep"
,
"6000"
}
containers
[
i
]
.
VolumeMounts
=
[]
api
.
VolumeMount
{
{
Name
:
"testpd"
,
MountPath
:
"/testpd"
,
},
}
containers
[
i
]
.
Resources
.
Limits
=
api
.
ResourceList
{}
containers
[
i
]
.
Resources
.
Limits
[
api
.
ResourceCPU
]
=
*
resource
.
NewQuantity
(
int64
(
0
),
resource
.
DecimalSI
)
}
pod
:=
&
api
.
Pod
{
pod
:=
&
api
.
Pod
{
TypeMeta
:
api
.
TypeMeta
{
TypeMeta
:
api
.
TypeMeta
{
Kind
:
"Pod"
,
Kind
:
"Pod"
,
...
@@ -294,20 +342,8 @@ func testPDPod(diskName, targetHost string, readOnly bool) *api.Pod {
...
@@ -294,20 +342,8 @@ func testPDPod(diskName, targetHost string, readOnly bool) *api.Pod {
Name
:
"pd-test-"
+
string
(
util
.
NewUUID
()),
Name
:
"pd-test-"
+
string
(
util
.
NewUUID
()),
},
},
Spec
:
api
.
PodSpec
{
Spec
:
api
.
PodSpec
{
Containers
:
[]
api
.
Container
{
Containers
:
containers
,
{
NodeName
:
targetHost
,
Name
:
"testpd"
,
Image
:
"gcr.io/google_containers/busybox"
,
Command
:
[]
string
{
"sleep"
,
"600"
},
VolumeMounts
:
[]
api
.
VolumeMount
{
{
Name
:
"testpd"
,
MountPath
:
"/testpd"
,
},
},
},
},
NodeName
:
targetHost
,
},
},
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment