mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-27 00:30:18 +00:00
991343d9e5
The only encoding version that exists is `1`. There is no need to have multiple constants for that version across different packages. Because there is only one version, `GenerateVolID()` does not really require it, and it can use a default version. If there is a need in the future to support an other encoding version, this can be revisited with a cleaner solution. Signed-off-by: Niels de Vos <ndevos@ibm.com>
169 lines
5.3 KiB
Go
169 lines
5.3 KiB
Go
/*
|
|
Copyright 2019 Ceph-CSI authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package util
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// defaultEncodingVersion is only one version for the encoding at the moment.
|
|
defaultEncodingVersion = uint16(1)
|
|
)
|
|
|
|
/*
|
|
CSIIdentifier contains the elements that form a CSI ID to be returned by the CSI plugin, and
|
|
contains enough information to decompose and extract required cluster and pool information to locate
|
|
the volume that relates to the CSI ID.
|
|
|
|
The CSI identifier is composed as elaborated in the comment against ComposeCSIID and thus,
|
|
DecomposeCSIID is the inverse of the same function.
|
|
|
|
The CSIIdentifier structure carries the following fields,
|
|
- LocationID: 64 bit integer identifier determining the location of the volume on the Ceph cluster.
|
|
It is the ID of the poolname or fsname, for RBD or CephFS backed volumes respectively.
|
|
- encodingVersion: Carries the version number of the encoding scheme used to encode the CSI ID,
|
|
and is preserved for any future proofing w.r.t changes in the encoding scheme, and to retain
|
|
ability to parse backward compatible encodings.
|
|
- ClusterID: Is a unique ID per cluster that the CSI instance is serving and is restricted to
|
|
lengths that can be accommodated in the encoding scheme.
|
|
- ObjectUUID: Is the on-disk uuid of the object (image/snapshot) name, for the CSI volume that
|
|
corresponds to this CSI ID.
|
|
*/
|
|
type CSIIdentifier struct {
|
|
LocationID int64
|
|
encodingVersion uint16
|
|
ClusterID string
|
|
ObjectUUID string
|
|
}
|
|
|
|
// This maximum comes from the CSI spec on max bytes allowed in the various CSI ID fields.
|
|
const maxVolIDLen = 128
|
|
|
|
const (
|
|
knownFieldSize = 64
|
|
uuidSize = 36
|
|
)
|
|
|
|
/*
|
|
ComposeCSIID composes a CSI ID from passed in parameters.
|
|
Version 1 of the encoding scheme is as follows,
|
|
|
|
[csi_id_version=1:4byte] + [-:1byte]
|
|
[length of clusterID=1:4byte] + [-:1byte]
|
|
[clusterID:36bytes (MAX)] + [-:1byte]
|
|
[poolID:16bytes] + [-:1byte]
|
|
[ObjectUUID:36bytes]
|
|
|
|
Total of constant field lengths, including '-' field separators would hence be,
|
|
4+1+4+1+1+16+1+36 = 64
|
|
*/
|
|
func (ci CSIIdentifier) ComposeCSIID() (string, error) {
|
|
buf16 := make([]byte, 2)
|
|
buf64 := make([]byte, 8)
|
|
|
|
if (knownFieldSize + len(ci.ClusterID)) > maxVolIDLen {
|
|
return "", errors.New("CSI ID encoding length overflow")
|
|
}
|
|
|
|
if len(ci.ObjectUUID) != uuidSize {
|
|
return "", errors.New("CSI ID invalid object uuid")
|
|
}
|
|
|
|
// set the encoding version, as it is not set by default anywhere else
|
|
encodingVersion := ci.encodingVersion
|
|
if encodingVersion == 0 {
|
|
encodingVersion = defaultEncodingVersion
|
|
}
|
|
|
|
binary.BigEndian.PutUint16(buf16, encodingVersion)
|
|
versionEncodedHex := hex.EncodeToString(buf16)
|
|
|
|
binary.BigEndian.PutUint16(buf16, uint16(len(ci.ClusterID)))
|
|
clusterIDLength := hex.EncodeToString(buf16)
|
|
|
|
binary.BigEndian.PutUint64(buf64, uint64(ci.LocationID))
|
|
poolIDEncodedHex := hex.EncodeToString(buf64)
|
|
|
|
return strings.Join([]string{
|
|
versionEncodedHex, clusterIDLength, ci.ClusterID,
|
|
poolIDEncodedHex, ci.ObjectUUID,
|
|
}, "-"), nil
|
|
}
|
|
|
|
/*
|
|
DecomposeCSIID composes a CSIIdentifier from passed in string.
|
|
*/
|
|
func (ci *CSIIdentifier) DecomposeCSIID(composedCSIID string) error {
|
|
bytesToProcess := uint16(len(composedCSIID))
|
|
|
|
// if length is less that expected constant elements, then bail out!
|
|
if bytesToProcess < knownFieldSize {
|
|
return errors.New("failed to decode CSI identifier, string underflow")
|
|
}
|
|
|
|
buf16, err := hex.DecodeString(composedCSIID[0:4])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ci.encodingVersion = binary.BigEndian.Uint16(buf16)
|
|
// 4 for version encoding and 1 for '-' separator
|
|
bytesToProcess -= 5
|
|
|
|
buf16, err = hex.DecodeString(composedCSIID[5:9])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
clusterIDLength := binary.BigEndian.Uint16(buf16)
|
|
// 4 for length encoding and 1 for '-' separator
|
|
bytesToProcess -= 5
|
|
|
|
if bytesToProcess < (clusterIDLength + 1) {
|
|
return errors.New("failed to decode CSI identifier, string underflow")
|
|
}
|
|
ci.ClusterID = composedCSIID[10 : 10+clusterIDLength]
|
|
// additional 1 for '-' separator
|
|
bytesToProcess -= (clusterIDLength + 1)
|
|
nextFieldStartIdx := (10 + clusterIDLength + 1)
|
|
|
|
// minLenToDecode is now 17 as composedCSIID should include
|
|
// at least 16 for poolID encoding and 1 for '-' separator.
|
|
const minLenToDecode = 17
|
|
if bytesToProcess < minLenToDecode {
|
|
return errors.New("failed to decode CSI identifier, string underflow")
|
|
}
|
|
buf64, err := hex.DecodeString(composedCSIID[nextFieldStartIdx : nextFieldStartIdx+16])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ci.LocationID = int64(binary.BigEndian.Uint64(buf64))
|
|
// 16 for poolID encoding and 1 for '-' separator
|
|
bytesToProcess -= 17
|
|
nextFieldStartIdx += 17
|
|
|
|
// has to be an exact match
|
|
if bytesToProcess != uuidSize {
|
|
return errors.New("failed to decode CSI identifier, string size mismatch")
|
|
}
|
|
ci.ObjectUUID = composedCSIID[nextFieldStartIdx : nextFieldStartIdx+uuidSize]
|
|
|
|
return err
|
|
}
|