Search code examples
pythonazurearcgisazure-pipelines-yamlgssapi

Arcgis & Python: Azure YAML pipeline fails with "Command 'krb5-config --libs gssapi' returned non-zero exit status 127."


I am deploying my Python code to an Azure Function with Python runtime 3.9, using the following yaml pipeline:

trigger:
  branches:
    include:
      - dev
      - test 
      - uat 
      - prod

pool:
  vmImage: ubuntu-latest

stages:
- stage: Build
  displayName: Build stage
  condition: always()
  jobs:
  - job: Build_Stage
    displayName: Build Stage
    steps:

    #Define Python Version
    - task: UsePythonVersion@0
      displayName: "Setting Python version to 3.9"
      inputs:
        versionSpec: '3.9'
        architecture: 'x64'    

    #Install Python packages 
    - bash: |
        if [ -f extensions.csproj ]
        then
            dotnet build extensions.csproj --output ./bin
        fi
        pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
      displayName: 'Install Python packages in venv'


    #Archive files to create zip folder for the build
    - task: ArchiveFiles@2
      displayName: 'Archive files to create zip folder for the build'
      inputs:
            rootFolderOrFile: '$(Build.SourcesDirectory)' #Change to '$(Build.SourcesDirectory)/FolderNameWithFunctionAppInside' if a new parent folder is added 
            includeRootFolder: false
            archiveType: 'zip'
            archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
            replaceExistingArchive: true
    
    #Publish zip to Azure Pipeline
    - task: PublishPipelineArtifact@1
      displayName: 'Publish zip Package to Azure Pipeline'
      inputs:
        targetPath: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
        artifactName: $(artifactName)
        artifactType: 'pipeline'

#Deploy to DEV
- stage: DEV
  displayName: Deploy to DEV
  dependsOn: Build
  variables:
  - group: <my-variable-group>
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/dev'))
  jobs:
  - job: Deploy
    steps:

      #Download artifact to make it available to this stage
      - task: DownloadPipelineArtifact@2
        inputs:
          source: 'current'
          path: '$(Pipeline.Workspace)' 

      #Deploy
      - task: AzureFunctionApp@1
        displayName: Deploy Linux function app
        inputs:
          azureSubscription: $(azureRmConnection.Id)
          appType: 'functionAppLinux'
          appName: $(functionAppName)
          package: '$(Pipeline.Workspace)/**/*.zip'
          deploymentMethod: auto


#Deploy to TEST
- stage: TEST
  displayName: Deploy to TEST
  dependsOn: Build
  variables:
  - group: <my-variable-group>
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/test'))
  jobs:
  - job: Deploy
    steps:
    
      #Download artifact to make it available to this stage
      - task: DownloadPipelineArtifact@2
        inputs:
          source: 'current'
          path: '$(Pipeline.Workspace)'    
      
      #Deploy
      - task: AzureFunctionApp@1
        displayName: Deploy Linux function app
        inputs:
          azureSubscription: $(azureRmConnection.Id)
          appType: 'functionAppLinux'
          appName: $(functionAppName)
          package: '$(Pipeline.Workspace)/**/*.zip'
          deploymentMethod: auto


#Deploy to UAT
- stage: UAT
  displayName: Deploy to UAT
  dependsOn: Build
  variables:
  - group: <my-variable-group>
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/uat'))
  jobs:
  - job: Deploy
    steps:
    
      #Download artifact to make it available to this stage
      - task: DownloadPipelineArtifact@2
        inputs:
          source: 'current'
          path: '$(Pipeline.Workspace)'    
      
      #Deploy
      - task: AzureFunctionApp@1
        displayName: Deploy Linux function app
        inputs:
          azureSubscription: $(azureRmConnection.Id)
          appType: 'functionAppLinux'
          appName: $(functionAppName)
          package: '$(Pipeline.Workspace)/**/*.zip'
          deploymentMethod: auto


#Deploy to PROD
- stage: PROD
  displayName: Deploy to PROD
  dependsOn: Build
  variables:
  - group: <my-variable-group>
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/prod'))
  jobs:
  - job: Deploy
    steps:
    
      #Download artifact to make it available to this stage
      - task: DownloadPipelineArtifact@2
        inputs:
          source: 'current'
          path: '$(Pipeline.Workspace)'    
      
      #Deploy
      - task: AzureFunctionApp@1
        displayName: Deploy Linux function app
        inputs:
          azureSubscription: $(azureRmConnection.Id)
          appType: 'functionAppLinux'
          appName: $(functionAppName)
          package: '$(Pipeline.Workspace)/**/*.zip'
          deploymentMethod: auto

When I trigger this pipeline, my build stage fails with an error message pointing at krb5-config:


        File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 351, in <module>
          main()
        File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 333, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
        File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 118, in get_requires_for_build_wheel
          return hook(config_settings)
        File "/tmp/pip-build-env-j844587_/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 338, in get_requires_for_build_wheel
          return self._get_build_requires(config_settings, requirements=['wheel'])
        File "/tmp/pip-build-env-j844587_/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 320, in _get_build_requires
          self.run_setup()
        File "/tmp/pip-build-env-j844587_/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 335, in run_setup
          exec(code, locals())
        File "<string>", line 109, in <module>
        File "<string>", line 22, in get_output
        File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/subprocess.py", line 424, in check_output
          return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
        File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/subprocess.py", line 528, in run
          raise CalledProcessError(retcode, process.args,
      subprocess.CalledProcessError: Command 'krb5-config --libs gssapi' returned non-zero exit status 127.
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error

× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.

note: This error originates from a subprocess, and is likely not a problem with pip.
##[error]Bash exited with code '1'.

Is there a way I can fix this?

EDIT

The requirements are as follows:

pip==22.3.1
azure-functions
azure-functions-durable
datetime
requests==2.28.1
arcgis==2.0.1
openpyxl==3.0.10
numpy

Solution

  • I found out that it works if the bash section of the pipeline is changed from this:

        #Install Python packages 
        - bash: |
            if [ -f extensions.csproj ]
            then
                dotnet build extensions.csproj --output ./bin
            fi
            pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
          displayName: 'Install Python packages in venv'
    

    to this, where the packages making the pipeline fail are installed before the other Python packages:

        #Install Python packages 
        - bash: |
            if [ -f extensions.csproj ]
            then
                dotnet build extensions.csproj --output ./bin
            fi
            sudo apt install -y libkrb5-dev
            pip install requests-kerberos
            pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
          displayName: 'Install Python packages in venv using inline Bash script'
    

    EDIT

    In the event a new Ubuntu image is released without updating the sources, the best course of action is to update the sources before installing the kerb5 packages, like so:

    sudo apt-get update && sudo apt-get install -yq libkrb5-dev

        #Install Python packages 
        - bash: |  
            if [ -f extensions.csproj ]
            then
                dotnet build extensions.csproj --output ./bin
            fi
            sudo apt-get update && sudo apt-get install -yq libkrb5-dev
            pip install requests-kerberos 
            pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
          displayName: 'Install Python packages in venv using inline Bash script'