Merge pull request #1337 from brendandburns/Sarsate-pd-support
Taking over PD support from sarsate
This commit is contained in:
@@ -92,6 +92,9 @@ type VolumeSource struct {
|
||||
HostDir *HostDir `yaml:"hostDir" json:"hostDir"`
|
||||
// EmptyDir represents a temporary directory that shares a pod's lifetime.
|
||||
EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir"`
|
||||
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
|
||||
// kubelet's host machine and then exposed to the pod.
|
||||
GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk"`
|
||||
}
|
||||
|
||||
// HostDir represents bare host directory volume.
|
||||
@@ -111,7 +114,28 @@ const (
|
||||
ProtocolUDP Protocol = "UDP"
|
||||
)
|
||||
|
||||
// Port represents a network port in a single container.
|
||||
// GCEPersistent Disk resource.
|
||||
// A GCE PD must exist and be formatted before mounting to a container.
|
||||
// The disk must also be in the same GCE project and zone as the kubelet.
|
||||
// A GCE PD can only be mounted as read/write once.
|
||||
type GCEPersistentDisk struct {
|
||||
// Unique name of the PD resource. Used to identify the disk in GCE
|
||||
PDName string `yaml:"pdName" json:"pdName"`
|
||||
// Required: Filesystem type to mount.
|
||||
// Must be a filesystem type supported by the host operating system.
|
||||
// Ex. "ext4", "xfs", "ntfs"
|
||||
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||
FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"`
|
||||
// Optional: Partition on the disk to mount.
|
||||
// If omitted, kubelet will attempt to mount the device name.
|
||||
// Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty.
|
||||
Partition int `yaml:"partition,omitempty" json:"partition,omitempty"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// Port represents a network port in a single container
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
// in a pod must have a unique name.
|
||||
|
@@ -90,6 +90,9 @@ type VolumeSource struct {
|
||||
HostDir *HostDir `yaml:"hostDir" json:"hostDir"`
|
||||
// EmptyDir represents a temporary directory that shares a pod's lifetime.
|
||||
EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir"`
|
||||
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
|
||||
// kubelet's host machine and then exposed to the pod.
|
||||
GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk"`
|
||||
}
|
||||
|
||||
// HostDir represents bare host directory volume.
|
||||
@@ -109,7 +112,28 @@ const (
|
||||
ProtocolUDP Protocol = "UDP"
|
||||
)
|
||||
|
||||
// Port represents a network port in a single container.
|
||||
// GCEPersistent Disk resource.
|
||||
// A GCE PD must exist before mounting to a container. The disk must
|
||||
// also be in the same GCE project and zone as the kubelet.
|
||||
// A GCE PD can only be mounted as read/write once.
|
||||
type GCEPersistentDisk struct {
|
||||
// Unique name of the PD resource. Used to identify the disk in GCE
|
||||
PDName string `yaml:"pdName" json:"pdName"`
|
||||
// Required: Filesystem type to mount.
|
||||
// Must be a filesystem type supported by the host operating system.
|
||||
// Ex. "ext4", "xfs", "ntfs"
|
||||
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||
FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"`
|
||||
// Optional: Partition on the disk to mount.
|
||||
// If omitted, kubelet will attempt to mount the device name.
|
||||
// Ex. For /dev/sda1, this field is "1", for /dev/sda, this field 0 or empty.
|
||||
Partition int `yaml:"partition,omitempty" json:"partition,omitempty"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// Port represents a network port in a single container
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
// in a pod must have a unique name.
|
||||
|
@@ -90,6 +90,9 @@ type VolumeSource struct {
|
||||
HostDir *HostDir `yaml:"hostDir" json:"hostDir"`
|
||||
// EmptyDir represents a temporary directory that shares a pod's lifetime.
|
||||
EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir"`
|
||||
// A persistent disk that is mounted to the
|
||||
// kubelet's host machine and then exposed to the pod.
|
||||
GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk"`
|
||||
}
|
||||
|
||||
// HostDir represents bare host directory volume.
|
||||
@@ -124,6 +127,27 @@ type Port struct {
|
||||
HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty"`
|
||||
}
|
||||
|
||||
// GCEPersistent Disk resource.
|
||||
// A GCE PD must exist before mounting to a container. The disk must
|
||||
// also be in the same GCE project and zone as the kubelet.
|
||||
// A GCE PD can only be mounted as read/write once.
|
||||
type GCEPersistentDisk struct {
|
||||
// Unique name of the PD resource. Used to identify the disk in GCE
|
||||
PDName string `yaml:"pdName" json:"pdName"`
|
||||
// Required: Filesystem type to mount.
|
||||
// Must be a filesystem type supported by the host operating system.
|
||||
// Ex. "ext4", "xfs", "ntfs"
|
||||
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||
FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"`
|
||||
// Optional: Partition on the disk to mount.
|
||||
// If omitted, kubelet will attempt to mount the device name.
|
||||
// Ex. For /dev/sda1, this field is "1", for /dev/sda, this field 0 or empty.
|
||||
Partition int `yaml:"partition,omitempty" json:"partition,omitempty"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// VolumeMount describes a mounting of a Volume within a container.
|
||||
type VolumeMount struct {
|
||||
// Required: This must match the Name of a Volume [above].
|
||||
|
@@ -175,6 +175,9 @@ type VolumeSource struct {
|
||||
HostDir *HostDir `json:"hostDir" yaml:"hostDir"`
|
||||
// EmptyDir represents a temporary directory that shares a pod's lifetime.
|
||||
EmptyDir *EmptyDir `json:"emptyDir" yaml:"emptyDir"`
|
||||
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
|
||||
// kubelet's host machine and then exposed to the pod.
|
||||
GCEPersistentDisk *GCEPersistentDisk `yaml:"persistentDisk" json:"persistentDisk"`
|
||||
}
|
||||
|
||||
// HostDir represents bare host directory volume.
|
||||
@@ -194,6 +197,27 @@ const (
|
||||
ProtocolUDP Protocol = "UDP"
|
||||
)
|
||||
|
||||
// GCEPersistent Disk resource.
|
||||
// A GCE PD must exist and be formatted before mounting to a container.
|
||||
// The disk must also be in the same GCE project and zone as the kubelet.
|
||||
// A GCE PD can only be mounted as read/write once.
|
||||
type GCEPersistentDisk struct {
|
||||
// Unique name of the PD resource. Used to identify the disk in GCE
|
||||
PDName string `yaml:"pdName" json:"pdName"`
|
||||
// Required: Filesystem type to mount.
|
||||
// Must be a filesystem type supported by the host operating system.
|
||||
// Ex. "ext4", "xfs", "ntfs"
|
||||
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||
FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"`
|
||||
// Optional: Partition on the disk to mount.
|
||||
// If omitted, kubelet will attempt to mount the device name.
|
||||
// Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty.
|
||||
Partition int `yaml:"partition,omitempty" json:"partition,omitempty"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// Port represents a network port in a single container.
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
|
@@ -64,6 +64,10 @@ func validateSource(source *api.VolumeSource) errs.ErrorList {
|
||||
numVolumes++
|
||||
//EmptyDirs have nothing to validate
|
||||
}
|
||||
if source.GCEPersistentDisk != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateGCEPersistentDisk(source.GCEPersistentDisk)...)
|
||||
}
|
||||
if numVolumes != 1 {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("", source))
|
||||
}
|
||||
@@ -80,6 +84,20 @@ func validateHostDir(hostDir *api.HostDir) errs.ErrorList {
|
||||
|
||||
var supportedPortProtocols = util.NewStringSet(string(api.ProtocolTCP), string(api.ProtocolUDP))
|
||||
|
||||
func validateGCEPersistentDisk(PD *api.GCEPersistentDisk) errs.ErrorList {
|
||||
allErrs := errs.ErrorList{}
|
||||
if PD.PDName == "" {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("PD.PDName", PD.PDName))
|
||||
}
|
||||
if PD.FSType == "" {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("PD.FSType", PD.FSType))
|
||||
}
|
||||
if PD.Partition < 0 || PD.Partition > 255 {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("PD.Partition", PD.Partition))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePorts(ports []api.Port) errs.ErrorList {
|
||||
allErrs := errs.ErrorList{}
|
||||
|
||||
@@ -373,5 +391,17 @@ func ValidateReplicationControllerState(state *api.ReplicationControllerState) e
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("replicas", state.Replicas))
|
||||
}
|
||||
allErrs = append(allErrs, ValidateManifest(&state.PodTemplate.DesiredState.Manifest).Prefix("podTemplate.desiredState.manifest")...)
|
||||
allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(state.PodTemplate.DesiredState.Manifest.Volumes).Prefix("podTemplate.desiredState.manifest")...)
|
||||
return allErrs
|
||||
}
|
||||
func ValidateReadOnlyPersistentDisks(volumes []api.Volume) errs.ErrorList {
|
||||
allErrs := errs.ErrorList{}
|
||||
for _, vol := range volumes {
|
||||
if vol.Source.GCEPersistentDisk != nil {
|
||||
if vol.Source.GCEPersistentDisk.ReadOnly == false {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("GCEPersistentDisk.ReadOnly", false))
|
||||
}
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
@@ -40,12 +40,13 @@ func TestValidateVolumes(t *testing.T) {
|
||||
{Name: "123", Source: &api.VolumeSource{HostDir: &api.HostDir{"/mnt/path2"}}},
|
||||
{Name: "abc-123", Source: &api.VolumeSource{HostDir: &api.HostDir{"/mnt/path3"}}},
|
||||
{Name: "empty", Source: &api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||
{Name: "gcepd", Source: &api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}},
|
||||
}
|
||||
names, errs := validateVolumes(successCase)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
if len(names) != 4 || !names.HasAll("abc", "123", "abc-123", "empty") {
|
||||
if len(names) != 5 || !names.HasAll("abc", "123", "abc-123", "empty", "gcepd") {
|
||||
t.Errorf("wrong names result: %v", names)
|
||||
}
|
||||
|
||||
@@ -552,7 +553,14 @@ func TestValidateReplicationController(t *testing.T) {
|
||||
},
|
||||
Labels: validSelector,
|
||||
}
|
||||
|
||||
invalidVolumePodTemplate := api.PodTemplate{
|
||||
DesiredState: api.PodState{
|
||||
Manifest: api.ContainerManifest{
|
||||
Version: "v1beta1",
|
||||
Volumes: []api.Volume{{Name: "gcepd", Source: &api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
successCases := []api.ReplicationController{
|
||||
{
|
||||
TypeMeta: api.TypeMeta{ID: "abc", Namespace: api.NamespaceDefault},
|
||||
@@ -609,6 +617,13 @@ func TestValidateReplicationController(t *testing.T) {
|
||||
ReplicaSelector: validSelector,
|
||||
},
|
||||
},
|
||||
"read-write presistent disk": {
|
||||
TypeMeta: api.TypeMeta{ID: "abc"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
ReplicaSelector: validSelector,
|
||||
PodTemplate: invalidVolumePodTemplate,
|
||||
},
|
||||
},
|
||||
"negative_replicas": {
|
||||
TypeMeta: api.TypeMeta{ID: "abc", Namespace: api.NamespaceDefault},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
@@ -628,6 +643,7 @@ func TestValidateReplicationController(t *testing.T) {
|
||||
field != "id" &&
|
||||
field != "namespace" &&
|
||||
field != "desiredState.replicaSelector" &&
|
||||
field != "GCEPersistentDisk.ReadOnly" &&
|
||||
field != "desiredState.replicas" {
|
||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||
}
|
||||
|
Reference in New Issue
Block a user