diff options
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/backup/znapzend.nix | 369 | ||||
-rw-r--r-- | nixos/modules/services/network-filesystems/beegfs.nix | 343 | ||||
-rw-r--r-- | nixos/modules/services/x11/desktop-managers/xfce.nix | 7 | ||||
-rw-r--r-- | nixos/modules/services/x11/hardware/libinput.nix | 2 |
5 files changed, 706 insertions, 16 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index ccc2a46456e8..700b3baaa906 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -403,6 +403,7 @@ ./services/monitoring/vnstat.nix ./services/monitoring/zabbix-agent.nix ./services/monitoring/zabbix-server.nix + ./services/network-filesystems/beegfs.nix ./services/network-filesystems/cachefilesd.nix ./services/network-filesystems/davfs2.nix ./services/network-filesystems/drbd.nix diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix index baf99930e3eb..762bb4b38675 100644 --- a/nixos/modules/services/backup/znapzend.nix +++ b/nixos/modules/services/backup/znapzend.nix @@ -1,39 +1,372 @@ { config, lib, pkgs, ... }: with lib; +with types; let + + # Converts a plan like + # { "1d" = "1h"; "1w" = "1d"; } + # into + # "1d=>1h,1w=>1d" + attrToPlan = attrs: concatStringsSep "," (builtins.attrValues ( + mapAttrs (n: v: "${n}=>${v}") attrs)); + + planDescription = '' + The znapzend backup plan to use for the source. + </para> + <para> + The plan specifies how often to backup and for how long to keep the + backups. It consists of a series of retention periodes to interval + associations: + </para> + <para> + <literal> + retA=>intA,retB=>intB,... + </literal> + </para> + <para> + Both intervals and retention periods are expressed in standard units + of time or multiples of them. You can use both the full name or a + shortcut according to the following listing: + </para> + <para> + <literal> + second|sec|s, minute|min, hour|h, day|d, week|w, month|mon|m, year|y + </literal> + </para> + <para> + See <citerefentry><refentrytitle>znapzendzetup</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more info. + ''; + planExample = "1h=>10min,1d=>1h,1w=>1d,1m=>1w,1y=>1m"; + + # A type for a string of the form number{b|k|M|G} + mbufferSizeType = str // { + check = x: str.check x && builtins.isList (builtins.match "^[0-9]+[bkMG]$" x); + description = "string of the form number{b|k|M|G}"; + }; + + # Type for a string that must contain certain other strings (the list parameter). + # Note that these would need regex escaping. + stringContainingStrings = list: let + matching = s: map (str: builtins.match ".*${str}.*" s) list; + in str // { + check = x: str.check x && all isList (matching x); + description = "string containing all of the characters ${concatStringsSep ", " list}"; + }; + + timestampType = stringContainingStrings [ "%Y" "%m" "%d" "%H" "%M" "%S" ]; + + destType = srcConfig: submodule ({ name, ... }: { + options = { + + label = mkOption { + type = str; + description = "Label for this destination. Defaults to the attribute name."; + }; + + plan = mkOption { + type = str; + description = planDescription; + example = planExample; + }; + + dataset = mkOption { + type = str; + description = "Dataset name to send snapshots to."; + example = "tank/main"; + }; + + host = mkOption { + type = nullOr str; + description = '' + Host to use for the destination dataset. Can be prefixed with + <literal>user@</literal> to specify the ssh user. + ''; + default = null; + example = "john@example.com"; + }; + + presend = mkOption { + type = nullOr str; + description = '' + Command to run before sending the snapshot to the destination. + Intended to run a remote script via <command>ssh</command> on the + destination, e.g. to bring up a backup disk or server or to put a + zpool online/offline. See also <option>postsend</option>. + ''; + default = null; + example = "ssh root@bserv zpool import -Nf tank"; + }; + + postsend = mkOption { + type = nullOr str; + description = '' + Command to run after sending the snapshot to the destination. + Intended to run a remote script via <command>ssh</command> on the + destination, e.g. to bring up a backup disk or server or to put a + zpool online/offline. See also <option>presend</option>. + ''; + default = null; + example = "ssh root@bserv zpool export tank"; + }; + }; + + config = { + label = mkDefault name; + plan = mkDefault srcConfig.plan; + }; + }); + + + + srcType = submodule ({ name, config, ... }: { + options = { + + enable = mkOption { + type = bool; + description = "Whether to enable this source."; + default = true; + }; + + recursive = mkOption { + type = bool; + description = "Whether to do recursive snapshots."; + default = false; + }; + + mbuffer = { + enable = mkOption { + type = bool; + description = "Whether to use <command>mbuffer</command>."; + default = false; + }; + + port = mkOption { + type = nullOr ints.u16; + description = '' + Port to use for <command>mbuffer</command>. + </para> + <para> + If this is null, it will run <command>mbuffer</command> through + ssh. + </para> + <para> + If this is not null, it will run <command>mbuffer</command> + directly through TCP, which is not encrypted but faster. In that + case the given port needs to be open on the destination host. + ''; + default = null; + }; + + size = mkOption { + type = mbufferSizeType; + description = '' + The size for <command>mbuffer</command>. + Supports the units b, k, M, G. + ''; + default = "1G"; + example = "128M"; + }; + }; + + presnap = mkOption { + type = nullOr str; + description = '' + Command to run before snapshots are taken on the source dataset, + e.g. for database locking/flushing. See also + <option>postsnap</option>. + ''; + default = null; + example = literalExample '' + ''${pkgs.mariadb}/bin/mysql -e "set autocommit=0;flush tables with read lock;\\! ''${pkgs.coreutils}/bin/sleep 600" & ''${pkgs.coreutils}/bin/echo $! > /tmp/mariadblock.pid ; sleep 10 + ''; + }; + + postsnap = mkOption { + type = nullOr str; + description = '' + Command to run after snapshots are taken on the source dataset, + e.g. for database unlocking. See also <option>presnap</option>. + ''; + default = null; + example = literalExample '' + ''${pkgs.coreutils}/bin/kill `''${pkgs.coreutils}/bin/cat /tmp/mariadblock.pid`;''${pkgs.coreutils}/bin/rm /tmp/mariadblock.pid + ''; + }; + + timestampFormat = mkOption { + type = timestampType; + description = '' + The timestamp format to use for constructing snapshot names. + The syntax is <literal>strftime</literal>-like. The string must + consist of the mandatory <literal>%Y %m %d %H %M %S</literal>. + Optionally <literal>- _ . :</literal> characters as well as any + alphanumeric character are allowed. If suffixed by a + <literal>Z</literal>, times will be in UTC. + ''; + default = "%Y-%m-%d-%H%M%S"; + example = "znapzend-%m.%d.%Y-%H%M%SZ"; + }; + + sendDelay = mkOption { + type = int; + description = '' + Specify delay (in seconds) before sending snaps to the destination. + May be useful if you want to control sending time. + ''; + default = 0; + example = 60; + }; + + plan = mkOption { + type = str; + description = planDescription; + example = planExample; + }; + + dataset = mkOption { + type = str; + description = "The dataset to use for this source."; + example = "tank/home"; + }; + + destinations = mkOption { + type = loaOf (destType config); + description = "Additional destinations."; + default = {}; + example = literalExample '' + { + local = { + dataset = "btank/backup"; + presend = "zpool import -N btank"; + postsend = "zpool export btank"; + }; + remote = { + host = "john@example.com"; + dataset = "tank/john"; + }; + }; + ''; + }; + }; + + config = { + dataset = mkDefault name; + }; + + }); + + ### Generating the configuration from here + cfg = config.services.znapzend; + + onOff = b: if b then "on" else "off"; + nullOff = b: if isNull b then "off" else toString b; + stripSlashes = replaceStrings [ "/" ] [ "." ]; + + attrsToFile = config: concatStringsSep "\n" (builtins.attrValues ( + mapAttrs (n: v: "${n}=${v}") config)); + + mkDestAttrs = dst: with dst; + mapAttrs' (n: v: nameValuePair "dst_${label}${n}" v) ({ + "" = optionalString (! isNull host) "${host}:" + dataset; + _plan = plan; + } // optionalAttrs (presend != null) { + _precmd = presend; + } // optionalAttrs (postsend != null) { + _pstcmd = postsend; + }); + + mkSrcAttrs = srcCfg: with srcCfg; { + enabled = onOff enable; + mbuffer = with mbuffer; if enable then "${pkgs.mbuffer}/bin/mbuffer" + + optionalString (port != null) ":${toString port}" else "off"; + mbuffer_size = mbuffer.size; + post_znap_cmd = nullOff postsnap; + pre_znap_cmd = nullOff presnap; + recursive = onOff recursive; + src = dataset; + src_plan = plan; + tsformat = timestampFormat; + zend_delay = toString sendDelay; + } // fold (a: b: a // b) {} ( + map mkDestAttrs (builtins.attrValues destinations) + ); + + files = mapAttrs' (n: srcCfg: let + fileText = attrsToFile (mkSrcAttrs srcCfg); + in { + name = srcCfg.dataset; + value = pkgs.writeText (stripSlashes srcCfg.dataset) fileText; + }) cfg.zetup; + in { options = { services.znapzend = { - enable = mkEnableOption "ZnapZend daemon"; + enable = mkEnableOption "ZnapZend ZFS backup daemon"; logLevel = mkOption { default = "debug"; example = "warning"; - type = lib.types.enum ["debug" "info" "warning" "err" "alert"]; - description = "The log level when logging to file. Any of debug, info, warning, err, alert. Default in daemonized form is debug."; + type = enum ["debug" "info" "warning" "err" "alert"]; + description = '' + The log level when logging to file. Any of debug, info, warning, err, + alert. Default in daemonized form is debug. + ''; }; logTo = mkOption { - type = types.str; + type = str; default = "syslog::daemon"; example = "/var/log/znapzend.log"; - description = "Where to log to (syslog::<facility> or <filepath>)."; + description = '' + Where to log to (syslog::<facility> or <filepath>). + ''; }; noDestroy = mkOption { - type = types.bool; + type = bool; default = false; description = "Does all changes to the filesystem except destroy."; }; autoCreation = mkOption { - type = types.bool; + type = bool; + default = false; + description = "Automatically create the destination dataset if it does not exists."; + }; + + zetup = mkOption { + type = loaOf srcType; + description = "Znapzend configuration."; + default = {}; + example = literalExample '' + { + "tank/home" = { + # Make snapshots of tank/home every hour, keep those for 1 day, + # keep every days snapshot for 1 month, etc. + plan = "1d=>1h,1m=>1d,1y=>1m"; + recursive = true; + # Send all those snapshots to john@example.com:rtank/john as well + destinations.remote = { + host = "john@example.com"; + dataset = "rtank/john"; + }; + }; + }; + ''; + }; + + pure = mkOption { + type = bool; + description = '' + Do not persist any stateful znapzend setups. If this option is + enabled, your previously set znapzend setups will be cleared and only + the ones defined with this module will be applied. + ''; default = false; - description = "Automatically create the dataset on dest if it does not exists."; }; }; }; @@ -49,12 +382,30 @@ in path = with pkgs; [ zfs mbuffer openssh ]; + preStart = optionalString cfg.pure '' + echo Resetting znapzend zetups + ${pkgs.znapzend}/bin/znapzendzetup list \ + | grep -oP '(?<=\*\*\* backup plan: ).*(?= \*\*\*)' \ + | xargs ${pkgs.znapzend}/bin/znapzendzetup delete + '' + concatStringsSep "\n" (mapAttrsToList (dataset: config: '' + echo Importing znapzend zetup ${config} for dataset ${dataset} + ${pkgs.znapzend}/bin/znapzendzetup import --write ${dataset} ${config} + '') files); + serviceConfig = { - ExecStart = "${pkgs.znapzend}/bin/znapzend --logto=${cfg.logTo} --loglevel=${cfg.logLevel} ${optionalString cfg.noDestroy "--nodestroy"} ${optionalString cfg.autoCreation "--autoCreation"}"; + ExecStart = let + args = concatStringsSep " " [ + "--logto=${cfg.logTo}" + "--loglevel=${cfg.logLevel}" + (optionalString cfg.noDestroy "--nodestroy") + (optionalString cfg.autoCreation "--autoCreation") + ]; in "${pkgs.znapzend}/bin/znapzend ${args}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; }; }; }; }; + + meta.maintainers = with maintainers; [ infinisil ]; } diff --git a/nixos/modules/services/network-filesystems/beegfs.nix b/nixos/modules/services/network-filesystems/beegfs.nix new file mode 100644 index 000000000000..a6a2ec6cbc36 --- /dev/null +++ b/nixos/modules/services/network-filesystems/beegfs.nix @@ -0,0 +1,343 @@ +{ config, lib, pkgs, ...} : + +with lib; + +let + cfg = config.services.beegfs; + + # functions for the generations of config files + + configMgmtd = name: cfg: pkgs.writeText "mgmt-${name}.conf" '' + storeMgmtdDirectory = ${cfg.mgmtd.storeDir} + storeAllowFirstRunInit = false + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + + ${cfg.mgmtd.extraConfig} + ''; + + configAdmon = name: cfg: pkgs.writeText "admon-${name}.conf" '' + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + + ${cfg.admon.extraConfig} + ''; + + configMeta = name: cfg: pkgs.writeText "meta-${name}.conf" '' + storeMetaDirectory = ${cfg.meta.storeDir} + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + storeAllowFirstRunInit = false + + ${cfg.mgmtd.extraConfig} + ''; + + configStorage = name: cfg: pkgs.writeText "storage-${name}.conf" '' + storeStorageDirectory = ${cfg.storage.storeDir} + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + storeAllowFirstRunInit = false + + ${cfg.storage.extraConfig} + ''; + + configHelperd = name: cfg: pkgs.writeText "helperd-${name}.conf" '' + connAuthFile = ${cfg.connAuthFile} + ${cfg.helperd.extraConfig} + ''; + + configClientFilename = name : "/etc/beegfs/client-${name}.conf"; + + configClient = name: cfg: '' + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + + ${cfg.client.extraConfig} + ''; + + serviceList = [ + { service = "admon"; cfgFile = configAdmon; } + { service = "meta"; cfgFile = configMeta; } + { service = "mgmtd"; cfgFile = configMgmtd; } + { service = "storage"; cfgFile = configStorage; } + ]; + + # functions to generate systemd.service entries + + systemdEntry = service: cfgFile: (mapAttrs' ( name: cfg: + (nameValuePair "beegfs-${service}-${name}" (mkIf cfg."${service}".enable { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" ]; + after = [ "network-online.target" ]; + serviceConfig = rec { + ExecStart = '' + ${pkgs.beegfs}/bin/beegfs-${service} \ + cfgFile=${cfgFile name cfg} \ + pidFile=${PIDFile} + ''; + PIDFile = "/run/beegfs-${service}-${name}.pid"; + TimeoutStopSec = "300"; + }; + }))) cfg); + + systemdHelperd = mapAttrs' ( name: cfg: + (nameValuePair "beegfs-helperd-${name}" (mkIf cfg.client.enable { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" ]; + after = [ "network-online.target" ]; + serviceConfig = rec { + ExecStart = '' + ${pkgs.beegfs}/bin/beegfs-helperd \ + cfgFile=${configHelperd name cfg} \ + pidFile=${PIDFile} + ''; + PIDFile = "/run/beegfs-helperd-${name}.pid"; + TimeoutStopSec = "300"; + }; + }))) cfg; + + # wrappers to beegfs tools. Avoid typing path of config files + utilWrappers = mapAttrsToList ( name: cfg: + ( pkgs.runCommand "beegfs-utils-${name}" { nativeBuildInputs = [ pkgs.makeWrapper ]; } '' + mkdir -p $out/bin + + makeWrapper ${pkgs.beegfs}/bin/beegfs-check-servers \ + $out/bin/beegfs-check-servers-${name} \ + --add-flags "-c ${configClientFilename name}" \ + --prefix PATH : ${lib.makeBinPath [ pkgs.beegfs ]} + + makeWrapper ${pkgs.beegfs}/bin/beegfs-ctl \ + $out/bin/beegfs-ctl-${name} \ + --add-flags "--cfgFile=${configClientFilename name}" + + makeWrapper ${pkgs.beegfs}/bin/beegfs-ctl \ + $out/bin/beegfs-df-${name} \ + --add-flags "--cfgFile=${configClientFilename name}" \ + --add-flags --listtargets \ + --add-flags --hidenodeid \ + --add-flags --pools \ + --add-flags --spaceinfo + + makeWrapper ${pkgs.beegfs}/bin/beegfs-fsck \ + $out/bin/beegfs-fsck-${name} \ + --add-flags "--cfgFile=${configClientFilename name}" + '' + )) cfg; +in +{ + ###### interface + + options = { + services.beegfsEnable = mkEnableOption "BeeGFS"; + + services.beegfs = mkOption { + default = {}; + description = '' + BeeGFS configurations. Every mount point requires a separate configuration. + ''; + type = with types; attrsOf (submodule ({ config, ... } : { + options = { + mgmtdHost = mkOption { + type = types.str; + default = null; + example = "master"; + description = ''Hostname of managament host.''; + }; + + connAuthFile = mkOption { + type = types.str; + default = ""; + example = "/etc/my.key"; + description = "File containing shared secret authentication."; + }; + + connPortShift = mkOption { + type = types.int; + default = 0; + example = 5; + description = '' + For each additional beegfs configuration shift all + service TCP/UDP ports by at least 5. + ''; + }; + + client = { + enable = mkEnableOption "BeeGFS client"; + + mount = mkOption { + type = types.bool; + default = true; + description = "Create fstab entry automatically"; + }; + + mountPoint = mkOption { + type = types.str; + default = "/run/beegfs"; + description = '' + Mount point under which the beegfs filesytem should be mounted. + If mounted manually the mount option specifing the config file is needed: + cfgFile=/etc/beegfs/beegfs-client-<name>.conf + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-client.conf. + See documentation for further details. + ''; + }; + }; + + helperd = { + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-helperd.conf. See documentation + for further details. + ''; + }; + }; + + mgmtd = { + enable = mkEnableOption "BeeGFS mgmtd daemon"; + + storeDir = mkOption { + type = types.path; + default = null; + example = "/data/beegfs-mgmtd"; + description = '' + Data directory for mgmtd. + Must not be shared with other beegfs daemons. + This directory must exist and it must be initialized + with beegfs-setup-mgmtd, e.g. "beegfs-setup-mgmtd -C -p <storeDir>" + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-mgmtd.conf. See documentation + for further details. + ''; + }; + }; + + admon = { + enable = mkEnableOption "BeeGFS admon daemon"; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-admon.conf. See documentation + for further details. + ''; + }; + }; + + meta = { + enable = mkEnableOption "BeeGFS meta data daemon"; + + storeDir = mkOption { + type = types.path; + default = null; + example = "/data/beegfs-meta"; + description = '' + Data directory for meta data service. + Must not be shared with other beegfs daemons. + The underlying filesystem must be mounted with xattr turned on. + This directory must exist and it must be initialized + with beegfs-setup-meta, e.g. + "beegfs-setup-meta -C -s <serviceID> -p <storeDir>" + ''; + }; + + extraConfig = mkOption { + type = types.str; + default = ""; + description = '' + Additional lines for beegfs-meta.conf. See documentation + for further details. + ''; + }; + }; + + storage = { + enable = mkEnableOption "BeeGFS storage daemon"; + + storeDir = mkOption { + type = types.path; + default = null; + example = "/data/beegfs-storage"; + description = '' + Data directories for storage service. + Must not be shared with other beegfs daemons. + The underlying filesystem must be mounted with xattr turned on. + This directory must exist and it must be initialized + with beegfs-setup-storage, e.g. + "beegfs-setup-storage -C -s <serviceID> -i <storageTargetID> -p <storeDir>" + ''; + }; + + extraConfig = mkOption { + type = types.str; + default = ""; + description = '' + Addional lines for beegfs-storage.conf. See documentation + for further details. + ''; + }; + }; + }; + })); + }; + }; + + ###### implementation + + config = + mkIf config.services.beegfsEnable { + + environment.systemPackages = utilWrappers; + + # Put the client.conf files in /etc since they are needed + # by the commandline tools + environment.etc = mapAttrs' ( name: cfg: + (nameValuePair "beegfs/client-${name}.conf" (mkIf (cfg.client.enable) + { + enable = true; + text = configClient name cfg; + }))) cfg; + + # Kernel module, we need it only once per host. + boot = mkIf ( + foldr (a: b: a || b) false + (map (x: x.client.enable) (collect (x: x ? client) cfg))) + { + kernelModules = [ "beegfs" ]; + extraModulePackages = [ pkgs.linuxPackages.beegfs-module ]; + }; + + # generate fstab entries + fileSystems = mapAttrs' (name: cfg: + (nameValuePair cfg.client.mountPoint (optionalAttrs cfg.client.mount (mkIf cfg.client.enable { + device = "beegfs_nodev"; + fsType = "beegfs"; + mountPoint = cfg.client.mountPoint; + options = [ "cfgFile=${configClientFilename name}" "_netdev" ]; + })))) cfg; + + # generate systemd services + systemd.services = systemdHelperd // + foldr (a: b: a // b) {} + (map (x: systemdEntry x.service x.cfgFile) serviceList); + }; +} diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix index 8c8f9a825ea2..9d5d03638e04 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -3,16 +3,13 @@ with lib; let - xcfg = config.services.xserver; pcfg = config.hardware.pulseaudio; cfg = xcfg.desktopManager.xfce; - in { options = { - services.xserver.desktopManager.xfce = { enable = mkOption { type = types.bool; @@ -125,9 +122,7 @@ in [ "/share/xfce4" "/share/themes" "/share/mime" "/share/desktop-directories" "/share/gtksourceview-2.0" ]; environment.variables.GIO_EXTRA_MODULES = [ "${pkgs.xfce.gvfs}/lib/gio/modules" ]; - environment.variables.GDK_PIXBUF_MODULE_FILE = [ - "$(echo ${pkgs.librsvg.out}/lib/gdk-pixbuf-*/*/loaders.cache)" - ]; + environment.variables.GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; # Enable helpful DBus services. services.udisks2.enable = true; diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix index 5aecdef812e6..d0a87f183b6f 100644 --- a/nixos/modules/services/x11/hardware/libinput.nix +++ b/nixos/modules/services/x11/hardware/libinput.nix @@ -170,7 +170,7 @@ in { disableWhileTyping = mkOption { type = types.bool; - default = true; + default = false; description = '' Disable input method while typing. |