addPriEx :: Bool               -- ^ Whether to override the N+1 and
                               -- other /soft/ checks, useful if we
                               -- come from a worse status
                               -- (e.g. offline)
         -> Node               -- ^ The target node
         -> Instance.Instance  -- ^ The instance to add
         -> T.OpResult Node    -- ^ The result of the operation,
                               -- either the new version of the node
                               -- or a failure mode
addPriEx force t inst =
  let iname = Instance.idx inst
      i_online = Instance.notOffline inst
      uses_disk = Instance.usesLocalStorage inst
      cur_dsk = fDsk t
      new_mem = decIf i_online (fMem t) (Instance.mem inst)
      new_dsk = decIf uses_disk cur_dsk (Instance.dsk inst)
      new_free_sp = calcNewFreeSpindles True t inst
      new_inst_sp = calcSpindleUse True t inst
      new_failn1 = new_mem <= rMem t
      new_ucpu = incIf i_online (uCpu t) (Instance.vcpus inst)
      new_pcpu = fromIntegral new_ucpu / tCpu t
      new_dp = computeNewPDsk t new_free_sp new_dsk
      l_cpu = T.iPolicyVcpuRatio $ iPolicy t
      new_load = utilLoad t `T.addUtil` Instance.util inst
      inst_tags = Instance.exclTags inst
      old_tags = pTags t
      strict = not force
  in case () of
       _ | new_mem <= 0 -> Bad T.FailMem
         | uses_disk && new_dsk <= 0 -> Bad T.FailDisk
         | uses_disk && new_dsk < loDsk t && strict -> Bad T.FailDisk
         | uses_disk && exclStorage t && new_free_sp < 0 -> Bad T.FailSpindles
         | uses_disk && new_inst_sp > hiSpindles t && strict -> Bad T.FailDisk
         | new_failn1 && not (failN1 t) && strict -> Bad T.FailMem
         | l_cpu >= 0 && l_cpu < new_pcpu && strict -> Bad T.FailCPU
         | rejectAddTags old_tags inst_tags -> Bad T.FailTags
         | otherwise ->
           let new_plist = iname:pList t
               new_mp = fromIntegral new_mem / tMem t
               r = t { pList = new_plist, fMem = new_mem, fDsk = new_dsk
                     , failN1 = new_failn1, pMem = new_mp, pDsk = new_dp
                     , uCpu = new_ucpu, pCpu = new_pcpu
                     , utilLoad = new_load
                     , pTags = addTags old_tags inst_tags
                     , instSpindles = new_inst_sp
                     , fSpindles = new_free_sp
                     }
           in Ok r

-- | Adds a secondary instance (basic version).
addPriEx :: Bool               -- ^ Whether to override the N+1 and
                               -- other /soft/ checks, useful if we
                               -- come from a worse status
                               -- (e.g. offline)
         -> Node               -- ^ The target node
         -> Instance.Instance  -- ^ The instance to add
         -> T.OpResult Node
addPriEx force t inst =
  let iname = Instance.idx inst
      i_online = Instance.notOffline inst
      uses_disk = Instance.usesLocalStorage inst
      cur_dsk = fDsk t
      new_mem = decIf i_online (fMem t) (Instance.mem inst)
      new_dsk = decIf uses_disk cur_dsk (Instance.dsk inst)
      new_free_sp = calcNewFreeSpindles True t inst
      new_inst_sp = calcSpindleUse True t inst
      new_failn1 = new_mem <= rMem t
      new_ucpu = incIf i_online (uCpu t) (Instance.vcpus inst)
      new_pcpu = fromIntegral new_ucpu / tCpu t
      new_dp = computeNewPDsk t new_free_sp new_dsk
      l_cpu = T.iPolicyVcpuRatio $ iPolicy t
      new_load = utilLoad t `T.addUtil` Instance.util inst
      inst_tags = Instance.exclTags inst
      old_tags = pTags t
      strict = not force
  in case () of
       _ | new_mem <= 0 -> Bad T.FailMem
         | uses_disk && new_dsk <= 0 -> Bad T.FailDisk
         | uses_disk && new_dsk < loDsk t && strict -> Bad T.FailDisk
         | uses_disk && exclStorage t && new_free_sp < 0 -> Bad T.FailSpindles
         | uses_disk && new_inst_sp > hiSpindles t && strict -> Bad T.FailDisk
         | new_failn1 && not (failN1 t) && strict -> Bad T.FailMem
         | l_cpu >= 0 && l_cpu < new_pcpu && strict -> Bad T.FailCPU
         | rejectAddTags old_tags inst_tags -> Bad T.FailTags
         | otherwise ->
           let new_plist = iname:pList t
               new_mp = fromIntegral new_mem / tMem t
               r = t { pList = new_plist, fMem = new_mem, fDsk = new_dsk
                     , failN1 = new_failn1, pMem = new_mp, pDsk = new_dp
                     , uCpu = new_ucpu, pCpu = new_pcpu
                     , utilLoad = new_load
                     , pTags = addTags old_tags inst_tags
                     , instSpindles = new_inst_sp
                     , fSpindles = new_free_sp
                     }
           in Ok r

-- | Adds a secondary instance (basic version).
addPriEx force t inst =
  let iname = Instance.idx inst
      i_online = Instance.notOffline inst
      uses_disk = Instance.usesLocalStorage inst
      cur_dsk = fDsk t
      new_mem = decIf i_online (fMem t) (Instance.mem inst)
      new_dsk = decIf uses_disk cur_dsk (Instance.dsk inst)
      new_free_sp = calcNewFreeSpindles True t inst
      new_inst_sp = calcSpindleUse True t inst
      new_failn1 = new_mem <= rMem t
      new_ucpu = incIf i_online (uCpu t) (Instance.vcpus inst)
      new_pcpu = fromIntegral new_ucpu / tCpu t
      new_dp = computeNewPDsk t new_free_sp new_dsk
      l_cpu = T.iPolicyVcpuRatio $ iPolicy t
      new_load = utilLoad t `T.addUtil` Instance.util inst
      inst_tags = Instance.exclTags inst
      old_tags = pTags t
      strict = not force
  in case () of
       _ | new_mem <= 0 -> Bad T.FailMem
         | uses_disk && new_dsk <= 0 -> Bad T.FailDisk
         | uses_disk && new_dsk < loDsk t && strict -> Bad T.FailDisk
         | uses_disk && exclStorage t && new_free_sp < 0 -> Bad T.FailSpindles
         | uses_disk && new_inst_sp > hiSpindles t && strict -> Bad T.FailDisk
         | new_failn1 && not (failN1 t) && strict -> Bad T.FailMem
         | l_cpu >= 0 && l_cpu < new_pcpu && strict -> Bad T.FailCPU
         | rejectAddTags old_tags inst_tags -> Bad T.FailTags
         | otherwise ->
           let new_plist = iname:pList t
               new_mp = fromIntegral new_mem / tMem t
               r = t { pList = new_plist, fMem = new_mem, fDsk = new_dsk
                     , failN1 = new_failn1, pMem = new_mp, pDsk = new_dp
                     , uCpu = new_ucpu, pCpu = new_pcpu
                     , utilLoad = new_load
                     , pTags = addTags old_tags inst_tags
                     , instSpindles = new_inst_sp
                     , fSpindles = new_free_sp
                     }
           in Ok r

-- | Adds a secondary instance (basic version).