in gce-containers-startup/volumes/volumes.go [194:243]
func (env Env) PrepareVolumesAndGetBindings(spec api.ContainerSpecStruct) (map[string][]HostPathBindConfiguration, error) {
// First, build maps that will allow to verify logical consistency:
// - All volumes must be referenced at least once.
// - All volume mounts must refer an existing volume.
volumesReferencesCount := map[string]int{}
volumeMountWantsReadWriteMap := map[string]bool{}
for _, apiVolume := range spec.Volumes {
volumesReferencesCount[apiVolume.Name] = 0
volumeMountWantsReadWriteMap[apiVolume.Name] = false
}
for containerIndex, container := range spec.Containers {
log.Printf("Found %d volume mounts in container %s declaration.", len(container.VolumeMounts), container.Name)
for _, volumeMount := range container.VolumeMounts {
if _, present := volumesReferencesCount[volumeMount.Name]; !present {
return nil, fmt.Errorf("Invalid container declaration: Volume %s referenced in container %s (index: %d) not found in volume definitions.", volumeMount.Name, container.Name, containerIndex)
} else {
volumesReferencesCount[volumeMount.Name] += 1
volumeMountWantsReadWriteMap[volumeMount.Name] = volumeMountWantsReadWriteMap[volumeMount.Name] || !volumeMount.ReadOnly
}
}
}
for volumeName, referenceCount := range volumesReferencesCount {
if referenceCount == 0 {
return nil, fmt.Errorf("Invalid container declaration: Volume %s not referenced by any container.", volumeName)
}
}
volumeNameToHostPathMap, volumeNameMapBuildingError := env.buildVolumeNameToHostPathMap(spec.Volumes, volumeMountWantsReadWriteMap)
if volumeNameMapBuildingError != nil {
return nil, volumeNameMapBuildingError
}
containerBindingConfigurationMap := map[string][]HostPathBindConfiguration{}
for _, container := range spec.Containers {
var hostPathBinds []HostPathBindConfiguration
for _, volumeMount := range container.VolumeMounts {
// It has already been checked that the volume is present.
volumeHostPathAndMode, _ := volumeNameToHostPathMap[volumeMount.Name]
if volumeHostPathAndMode.readOnly && !volumeMount.ReadOnly {
return nil, fmt.Errorf("Container %s: volumeMount %s specifies read-write access, but underlying volume is read-only.", container.Name, volumeMount.Name)
}
hostPathBinds = append(hostPathBinds, HostPathBindConfiguration{HostPath: volumeHostPathAndMode.hostPath, ContainerPath: volumeMount.MountPath, ReadOnly: volumeMount.ReadOnly})
}
containerBindingConfigurationMap[container.Name] = hostPathBinds
}
return containerBindingConfigurationMap, nil
}