diff --git a/autotools/build-bash-completion b/autotools/build-bash-completion
index 838b9f66ab5434f3d82e97e92c6b82155e7da8e8..6f39ef5d4ccbc9dcdeff17673babe1fd0a2a9df1 100755
--- a/autotools/build-bash-completion
+++ b/autotools/build-bash-completion
@@ -273,12 +273,15 @@ class CompletionWriter:
       if not suggest:
         suggest = opt.choices
 
-      if suggest:
-        suggest_text = " ".join(sorted(suggest))
+      if (isinstance(suggest, (int, long)) and
+          suggest in cli.OPT_COMPL_ALL):
+        key = suggest
+      elif suggest:
+        key = " ".join(sorted(suggest))
       else:
-        suggest_text = ""
+        key = ""
 
-      values.setdefault(suggest_text, []).extend(opt.all_names)
+      values.setdefault(key, []).extend(opt.all_names)
 
     # Don't write any code if there are no option values
     if not values:
@@ -301,7 +304,19 @@ class CompletionWriter:
                utils.ShellQuote("|".join(allnames)))
       sw.IncIndent()
       try:
-        WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
+        if suggest == cli.OPT_COMPL_MANY_NODES:
+          # TODO: Implement comma-separated values
+          WriteCompReply(sw, "-W ''", cur=cur)
+        elif suggest == cli.OPT_COMPL_ONE_NODE:
+          WriteCompReply(sw, "-W \"$(_ganeti_nodes)\"", cur=cur)
+        elif suggest == cli.OPT_COMPL_ONE_INSTANCE:
+          WriteCompReply(sw, "-W \"$(_ganeti_instances)\"", cur=cur)
+        elif suggest == cli.OPT_COMPL_ONE_OS:
+          WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)
+        elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:
+          WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)
+        else:
+          WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
       finally:
         sw.DecIndent()
 
diff --git a/lib/cli.py b/lib/cli.py
index cd3c26eff67fb5b18ba099b7dcbaf82f5690e437..2bbd4fba51a812f1e1f903bdfa663172ae002043 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -56,6 +56,9 @@ __all__ = ["DEBUG_OPT", "NOHDR_OPT", "SEP_OPT", "GenericMain",
            "ArgInstance", "ArgNode", "ArgChoice", "ArgHost",
            "ARGS_NONE", "ARGS_ONE_INSTANCE", "ARGS_ONE_NODE",
            "ARGS_MANY_INSTANCES", "ARGS_MANY_NODES",
+           "OPT_COMPL_ONE_NODE", "OPT_COMPL_ONE_INSTANCE",
+           "OPT_COMPL_MANY_NODES",
+           "OPT_COMPL_ONE_OS", "OPT_COMPL_ONE_IALLOCATOR",
            ]
 
 NO_PREFIX = "no_"
@@ -330,6 +333,23 @@ def check_key_val(option, opt, value):
   return _SplitKeyVal(opt, value)
 
 
+# completion_suggestion is normally a list. Using numeric values not evaluating
+# to False for dynamic completion.
+(OPT_COMPL_MANY_NODES,
+ OPT_COMPL_ONE_NODE,
+ OPT_COMPL_ONE_INSTANCE,
+ OPT_COMPL_ONE_OS,
+ OPT_COMPL_ONE_IALLOCATOR) = range(100, 105)
+
+OPT_COMPL_ALL = frozenset([
+  OPT_COMPL_MANY_NODES,
+  OPT_COMPL_ONE_NODE,
+  OPT_COMPL_ONE_INSTANCE,
+  OPT_COMPL_ONE_OS,
+  OPT_COMPL_ONE_IALLOCATOR,
+  ])
+
+
 class CliOption(Option):
   """Custom option class for optparse.