Revision 11e90588

b/lib/network.py
26 26
import ipaddr
27 27

  
28 28
from bitarray import bitarray
29
from base64 import b64encode
30
from base64 import b64decode
29 31

  
30 32
from ganeti import errors
31 33

  
......
92 94
      self.gateway6 = ipaddr.IPv6Address(self.net.gateway6)
93 95

  
94 96
    if self.net.reservations:
95
      self.reservations = bitarray(self.net.reservations)
97
      self.reservations = bitarray()
98
      # pylint: disable=E1103
99
      self.reservations.frombytes(b64decode(self.net.reservations))
96 100
    else:
97 101
      self.reservations = bitarray(self.network.numhosts)
98 102
      # pylint: disable=E1103
99 103
      self.reservations.setall(False)
100 104

  
101 105
    if self.net.ext_reservations:
102
      self.ext_reservations = bitarray(self.net.ext_reservations)
106
      self.ext_reservations = bitarray()
107
      # pylint: disable=E1103
108
      self.ext_reservations.frombytes(b64decode(self.net.ext_reservations))
103 109
    else:
104 110
      self.ext_reservations = bitarray(self.network.numhosts)
105 111
      # pylint: disable=E1103
......
129 135

  
130 136
    """
131 137
    # pylint: disable=E1103
132
    self.net.ext_reservations = self.ext_reservations.to01()
133
    self.net.reservations = self.reservations.to01()
138
    self.net.ext_reservations = b64encode(self.ext_reservations.tobytes())
139
    self.net.reservations = b64encode(self.reservations.tobytes())
134 140

  
135 141
  def _Mark(self, address, value=True, external=False):
136 142
    idx = self._GetAddrIndex(address)
b/src/Ganeti/Network.hs
41 41
import qualified Data.Vector.Unboxed as V
42 42

  
43 43
import Ganeti.Objects
44
import Ganeti.Utils (b64StringToBitString)
44 45

  
45 46
-- | An address pool, holding a network plus internal and external
46 47
-- reservations.
......
75 76
-- | Converts a maybe bit string to a bit vector. Returns an empty bit vector on
76 77
-- nothing.
77 78
maybeStr2BitVec :: Maybe String -> V.Vector Bool
78
maybeStr2BitVec (Just s) = bitStringToBitVector s
79
maybeStr2BitVec (Just s) = bitStringToBitVector $ b64StringToBitString s
79 80
maybeStr2BitVec Nothing = V.fromList ([]::[Bool])
80 81

  
81 82
-- | Converts a string to a bit vector. The character '0' is interpreted
b/src/Ganeti/Query/Network.hs
46 46
import Ganeti.Query.Common
47 47
import Ganeti.Query.Types
48 48
import Ganeti.Types
49
import Ganeti.Utils (b64StringToBitString)
49 50

  
50 51
-- | There is no actual runtime.
51 52
data Runtime = Runtime
......
175 176
getExtReservationsString :: Network -> ResultEntry
176 177
getExtReservationsString net =
177 178
  let addrs = getReservations (networkNetwork net)
178
              (fromMaybe "" $ networkExtReservations net)
179
              (b64StringToBitString $ fromMaybe "" $ networkExtReservations net)
179 180
  in rsNormal . intercalate ", " $ map show addrs
180 181

  
181 182
-- | Dummy function for collecting live data (which networks don't have).
b/src/Ganeti/Utils.hs
58 58
  , splitEithers
59 59
  , recombineEithers
60 60
  , setOwnerAndGroupFromNames
61
  , b64StringToBitString
62
  , bitStringToB64String
61 63
  ) where
62 64

  
63 65
import Data.Char (toUpper, isAlphaNum, isDigit, isSpace)
......
77 79
import System.Posix.Files
78 80
import System.Time
79 81

  
82
import qualified Data.ByteString as BS
83
import Data.ByteString.Base64 (decodeLenient, encode)
84
import qualified Data.ByteString.Char8 as BSC
85
import Data.Word (Word8)
86
import Data.Char (intToDigit, digitToInt)
87
import Numeric (showIntAtBase, readInt)
88

  
80 89
-- * Debug functions
81 90

  
82 91
-- | To be used only for debugging, breaks referential integrity.
......
458 467
  let uid = fst ents M.! daemon
459 468
  let gid = snd ents M.! dGroup
460 469
  setOwnerAndGroup filename uid gid
470

  
471
type BitString = String
472

  
473
-- | Base 64 encoded String to BitString
474
wordsToBitString :: [Word8] -> BitString
475
wordsToBitString =
476
    concatMap (padBits . wordToBits)
477
  where
478
    wordToBits = flip (showIntAtBase 2 intToDigit) ""
479
    padBits bs = replicate (8 - length bs) '0' ++ bs
480

  
481
decodeB64String :: String -> [Word8]
482
decodeB64String = BS.unpack . decodeLenient . BSC.pack
483

  
484
b64StringToBitString :: String -> BitString
485
b64StringToBitString = wordsToBitString . decodeB64String
486

  
487
-- | A BitString to Base 64 encoded String
488
bitStringToWords :: BitString -> [Word8]
489
bitStringToWords [] = []
490
bitStringToWords bs =
491
    bitStringToWord c : bitStringToWords rest
492
  where
493
    bitStringToWord = fst . head . readInt 2 (const True) digitToInt
494
    (c, rest) = splitAt 8 bs
495

  
496
encodeB64String :: [Word8] -> String
497
encodeB64String = BSC.unpack . encode . BS.pack
498

  
499
bitStringToB64String :: BitString -> String
500
bitStringToB64String  = encodeB64String . bitStringToWords
b/test/hs/Test/Ganeti/Objects.hs
62 62
import Ganeti.Objects as Objects
63 63
import Ganeti.JSON
64 64
import Ganeti.Types
65
import Ganeti.Utils (bitStringToB64String)
65 66

  
66 67
-- * Arbitrary instances
67 68

  
......
238 239
genValidNetwork :: Gen Objects.Network
239 240
genValidNetwork = do
240 241
  -- generate netmask for the IPv4 network
241
  netmask <- fromIntegral <$> choose (24::Int, 30)
242
  netmask <- fromIntegral <$> choose (24::Int, 29)
242 243
  name <- genName >>= mkNonEmpty
243 244
  mac_prefix <- genMaybe genName
244 245
  net <- arbitrary
245 246
  net6 <- genMaybe genIp6Net
246 247
  gateway <- genMaybe arbitrary
247 248
  gateway6 <- genMaybe genIp6Addr
248
  res <- liftM Just (genBitString $ netmask2NumHosts netmask)
249
  ext_res <- liftM Just (genBitString $ netmask2NumHosts netmask)
249
  res <- liftM (Just . bitStringToB64String)
250
         (genBitString $ netmask2NumHosts netmask)
251
  ext_res <- liftM (Just . bitStringToB64String)
252
             (genBitString $ netmask2NumHosts netmask)
250 253
  uuid <- arbitrary
251 254
  ctime <- arbitrary
252 255
  mtime <- arbitrary
b/tools/cfgupgrade
34 34
import logging
35 35
import time
36 36
from cStringIO import StringIO
37
from bitarray import bitarray
38
from base64 import b64encode, b64decode
37 39

  
38 40
from ganeti import constants
39 41
from ganeti import serializer
......
126 128
  _FillIPolicySpecs(default_ipolicy, ipolicy)
127 129

  
128 130

  
131
# pylint: disable=E1101
129 132
def UpgradeNetworks(config_data):
130
  networks = config_data.get("networks", None)
133
  networks = config_data.get("networks", {})
131 134
  if not networks:
132 135
    config_data["networks"] = {}
136
  for nobj in networks.values():
137
    for key in ("reservations", "ext_reservations"):
138
      r = nobj[key]
139
      if options.tob64:
140
        try:
141
          b = bitarray(r)
142
          nobj[key] = b64encode(b.tobytes())
143
        except ValueError:
144
          print("No 01 network found! Probably already in base64.")
145
      if options.to01:
146
        try:
147
          b = bitarray(r)
148
          print("01 network found! Do nothing.")
149
        except ValueError:
150
          b = bitarray()
151
          b.frombytes(b64decode(r))
152
          nobj[key] = b.to01()
153
      print("%s: %s -> %s" % (nobj["name"], r, nobj[key]))
133 154

  
134 155

  
135 156
def UpgradeCluster(config_data):
......
395 416
  parser.add_option("--downgrade",
396 417
                    help="Downgrade to the previous stable version",
397 418
                    action="store_true", dest="downgrade", default=False)
419
  parser.add_option("--tob64",
420
                    help="Change to base64 encoded networks",
421
                    action="store_true", dest="tob64", default=False)
422
  parser.add_option("--to01",
423
                    help="Change to non encoded networks (01 bitarrays)",
424
                    action="store_true", dest="to01", default=False)
398 425
  (options, args) = parser.parse_args()
399 426

  
400 427
  # We need to keep filenames locally because they might be renamed between

Also available in: Unified diff