Unverified Commit 38475aff authored by Pol Dellaiera's avatar Pol Dellaiera Committed by GitHub
Browse files

Merge pull request #276695 from katexochen/azure-cli/plugins

azure-cli: immutable command index & add extensions
parents ffda970d aacf05da
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -235,6 +235,16 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m

- The legacy and long deprecated systemd target `network-interfaces.target` has been removed. Use `network.target` instead.

- `azure-cli` now has extension support. For example, to install the `aks-preview` extension, use

  ```nix
  environment.systemPackages = [
    (azure-cli.withExtensions [ azure-cli.extensions.aks-preview ]);
  ];
  ```
  To make the `azure-cli` immutable and prevent clashes in case `azure-cli` is also installed via other package managers, some configuration files were moved into the derivation.
  This can be disabled by overriding `withImmutableConfig = false` when building `azure-cli`.

- `services.frp.settings` now generates the frp configuration file in TOML format as [recommended by upstream](https://github.com/fatedier/frp#configuration-files), instead of the legacy INI format. This has also introduced other changes in the configuration file structure and options.
  - The `settings.common` section in the configuration is no longer valid and all the options form inside it now goes directly under `settings`.
  - The `_` separating words in the configuration options is removed so the options are now in camel case. For example: `server_addr` becomes `serverAddr`, `server_port` becomes `serverPort` etc.
+98 −0
Original line number Diff line number Diff line
From c12adfdefd8a091e1fa870305a3cc61de6426914 Mon Sep 17 00:00:00 2001
From: Paul Meyer <49727155+katexochen@users.noreply.github.com>
Date: Thu, 14 Dec 2023 21:16:20 +0100
Subject: [PATCH] optional immutable configuration dir

Adding the possibility to configure an immutable configuration dir via
env variable `AZURE_IMMUTABLE_DIR`. This path is used for the files
that configure the dynamic behavior of the CLI code.
An immutable session is used for these files to ensure we don't try to
write to them.

Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
---
 azure/cli/core/__init__.py |  5 +++--
 azure/cli/core/_session.py | 19 ++++++++++++++++---
 .../cli/core/extension/dynamic_install.py     |  3 ++-
 3 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/azure/cli/core/__init__.py b/azure/cli/core/__init__.py
index d112633ec..20b6d045b 100644
--- a/azure/cli/core/__init__.py
+++ b/azure/cli/core/__init__.py
@@ -75,12 +75,13 @@ class AzCli(CLI):
         self.data['query_active'] = False

         azure_folder = self.config.config_dir
+        azure_immutable_folder = os.environ.get('AZURE_IMMUTABLE_DIR', azure_folder)
         ensure_dir(azure_folder)
         ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json'))
         CONFIG.load(os.path.join(azure_folder, 'az.json'))
         SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600)
-        INDEX.load(os.path.join(azure_folder, 'commandIndex.json'))
-        VERSIONS.load(os.path.join(azure_folder, 'versionCheck.json'))
+        INDEX.load(os.path.join(azure_immutable_folder, 'commandIndex.json'))
+        VERSIONS.load(os.path.join(azure_immutable_folder, 'versionCheck.json'))
         handle_version_update()

         self.cloud = get_active_cloud(self)
diff --git a/azure/cli/core/_session.py b/azure/cli/core/_session.py
index 471a0344c..acaef6fb8 100644
--- a/azure/cli/core/_session.py
+++ b/azure/cli/core/_session.py
@@ -85,6 +85,19 @@ class Session(MutableMapping):
         return len(self.data)


+class ImmutableSession(Session):
+    """
+    A session that is backed by an immutable JSON file. This session is read-only.
+    """
+    def save(self):
+        if os.getenv('AZURE_IMMUTABLE_DIR'):
+            get_logger(__name__).log(logging.DEBUG,
+                                     "Skipping update of file %s due to immutable directory.",
+                                     self.filename)
+            return
+        super().save()
+
+
 # ACCOUNT contains subscriptions information
 ACCOUNT = Session()

@@ -95,16 +108,16 @@ CONFIG = Session()
 SESSION = Session()

 # INDEX contains {top-level command: [command_modules and extensions]} mapping index
-INDEX = Session()
+INDEX = ImmutableSession()

 # VERSIONS provides local versions and pypi versions.
 # DO NOT USE it to get the current version of azure-cli,
 # it could be lagged behind and can be used to check whether
 # an upgrade of azure-cli happens
-VERSIONS = Session()
+VERSIONS = ImmutableSession()

 # EXT_CMD_TREE provides command to extension name mapping
-EXT_CMD_TREE = Session()
+EXT_CMD_TREE = ImmutableSession()

 # CLOUD_ENDPOINTS provides endpoints/suffixes of clouds
 CLOUD_ENDPOINTS = Session()
diff --git a/azure/cli/core/extension/dynamic_install.py b/azure/cli/core/extension/dynamic_install.py
index cb03980a0..29279be2b 100644
--- a/azure/cli/core/extension/dynamic_install.py
+++ b/azure/cli/core/extension/dynamic_install.py
@@ -17,7 +17,8 @@ def _get_extension_command_tree(cli_ctx):
     VALID_SECOND = 3600 * 24 * 10
     if not cli_ctx:
         return None
-    EXT_CMD_TREE.load(os.path.join(cli_ctx.config.config_dir, 'extensionCommandTree.json'), VALID_SECOND)
+    azure_immutable_folder = os.environ.get('AZURE_IMMUTABLE_DIR', cli_ctx.config.config_dir)
+    EXT_CMD_TREE.load(os.path.join(azure_immutable_folder, 'extensionCommandTree.json'), VALID_SECOND)
     if not EXT_CMD_TREE.data:
         import posixpath
         import requests
--
2.42.0
+75 −3
Original line number Diff line number Diff line
{ lib
, callPackage
, callPackages
, stdenvNoCC
, fetchurl
, fetchFromGitHub
, installShellFiles
, python3

  # Whether to include patches that enable placing certain behavior-defining
  # configuration files in the Nix store.
, withImmutableConfig ? true

  # List of extensions/plugins to include.
, withExtensions ? [ ]

, azure-cli
}:

let
@@ -17,9 +30,52 @@ let

  # put packages that needs to be overridden in the py package scope
  py = callPackage ./python-packages.nix { inherit src version; };

  # Builder for Azure CLI extensions. Extensions are Python wheels that
  # outside of nix would be fetched by the CLI itself from various sources.
  mkAzExtension =
    { pname
    , version
    , url
    , sha256
    , description
    }: python3.pkgs.buildPythonPackage {
      inherit pname version;
      format = "wheel";
      src = fetchurl { inherit url sha256; };
      meta = with lib; {
        inherit description;
        inherit (azure-cli.meta) platforms maintainers;
        homepage = "https://github.com/Azure/azure-cli-extensions";
        changelog = "https://github.com/Azure/azure-cli-extensions/blob/main/src/${pname}/HISTORY.rst";
        license = lib.licenses.mit;
        sourceProvenance = [ sourceTypes.fromSource ];
      };
    };

  extensions = callPackages ./extensions-generated.nix { inherit mkAzExtension; };

  extensionDir = stdenvNoCC.mkDerivation {
    name = "azure-cli-extensions";
    dontUnpack = true;
    installPhase =
      let
        namePaths = map (p: "${p.pname},${p}/${python3.sitePackages}") withExtensions;
      in
      ''
        for line in ${lib.concatStringsSep " " namePaths}; do
          name=$(echo $line | cut -d',' -f1)
          path=$(echo $line | cut -d',' -f2)
          mkdir -p $out/$name
          for f in $(ls $path); do
            ln -s $path/$f $out/$name/$f
          done
        done
      '';
  };
in

py.pkgs.toPythonApplication (py.pkgs.buildAzureCliPackage {
py.pkgs.toPythonApplication (py.pkgs.buildAzureCliPackage rec {
  pname = "azure-cli";
  inherit version src;

@@ -177,7 +233,13 @@ py.pkgs.toPythonApplication (py.pkgs.buildAzureCliPackage {
      --replace register-python-argcomplete ${py.pkgs.argcomplete}/bin/register-python-argcomplete
    installShellCompletion --bash --name az.bash az.completion.sh
    installShellCompletion --zsh --name _az az.completion.sh

  '' + lib.optionalString withImmutableConfig ''
    export HOME=$TMPDIR
    $out/bin/az --version
    mkdir -p $out/etc/azure
    mv $TMPDIR/.azure/commandIndex.json $out/etc/azure/commandIndex.json
    mv $TMPDIR/.azure/versionCheck.json $out/etc/azure/versionCheck.json
  '' + ''
    # remove garbage
    rm $out/bin/az.bat
    rm $out/bin/az.completion.sh
@@ -187,7 +249,12 @@ py.pkgs.toPythonApplication (py.pkgs.buildAzureCliPackage {
  # it's just a shebang script which calls `python -m azure.cli "$@"`
  postFixup = ''
    wrapProgram $out/bin/az \
      --set PYTHONPATH $PYTHONPATH
  '' + lib.optionalString withImmutableConfig ''
    --set AZURE_IMMUTABLE_DIR $out/etc/azure \
  '' + lib.optionalString (withExtensions != [ ]) ''
    --set AZURE_EXTENSION_DIR ${extensionDir} \
  '' + ''
    --set PYTHONPATH "${python3.pkgs.makePythonPath propagatedBuildInputs}:$out/${python3.sitePackages}"
  '';

  doInstallCheck = true;
@@ -270,6 +337,11 @@ py.pkgs.toPythonApplication (py.pkgs.buildAzureCliPackage {
    "azure.storage.common"
  ];

  passthru = {
    inherit extensions;
    withExtensions = extensions: azure-cli.override { withExtensions = extensions; };
  };

  meta = with lib; {
    homepage = "https://github.com/Azure/azure-cli";
    description = "Next generation multi-platform command line experience for Azure";
+982 −0

File added.

Preview size limit exceeded, changes collapsed.

+12 −1
Original line number Diff line number Diff line
{ stdenv
{ lib
, stdenv
, python3
, fetchPypi
, fetchpatch
@@ -30,6 +31,16 @@ let

        sourceRoot = "${src.name}/src/azure-cli-core";

        patches = [
          # Adding the possibility to configure an immutable configuration dir via `AZURE_IMMUTABLE_DIR`.
          # This enables us to place configuration files that alter the behavior of the CLI in the Nix store.
          #
          # This is a downstream patch without an commit or PR upstream.
          # There is an issue to discuss possible solutions upstream:
          # https://github.com/Azure/azure-cli/issues/28093
          ./0001-optional-immutable-configuration-dir.patch
        ];

        propagatedBuildInputs = with self; [
          argcomplete
          azure-cli-telemetry
Loading