public/Add-PulpContentUnit.ps1

# .ExternalHelp powershell-pulp-help.xml
Function Add-PulpContentUnit {
 [Cmdletbinding(DefaultParameterSetName='StringsPath')]
  Param(
    [Parameter(Mandatory=$false)]
    [string]$Server = (Get-PulpLocalConfig -Server).Server,

    [Parameter(Mandatory=$false)]
    [int]$Port = (Get-PulpLocalConfig -Port).Port,

    [Parameter(Mandatory=$false)]
    [string]$Protocol = (Get-PulpLocalConfig -Protocol).Protocol,

    [Parameter(Mandatory=$false)]
    [string]$AuthenticationMethod = (Get-PulpLocalConfig -AuthenticationMethod).AuthenticationMethod,

    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="ObjectsPath")]
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="ObjectsUrl")]
    [PSCustomObject[]]$TargetRepo,

    [Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true, ParameterSetName="StringsPath")]
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="StringsUrl")]
    [string[]]$TargetRepoId,

    [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$false, ParameterSetName="ObjectsPath")]
    [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$false, ParameterSetName="StringsPath")]
    [string[]]$Path,

    [Parameter(Mandatory=$true, ValueFromPipeline=$false, ParameterSetName="ObjectsUrl")]
    [Parameter(Mandatory=$true, ValueFromPipeline=$false, ParameterSetName="StringsUrl")]
    [string]$Url,

    [Parameter(Mandatory=$false)]
    [switch]$NoPublish,

    [Parameter(Mandatory=$true)]
    [string]$Type
  )
  Begin {
    If ($Type -eq 'puppet'){ $unitType = 'puppet_module' }
    Else { $unitType = $Type }
    # Do downloads
    If ($Url) {
       $null = New-Item -Type Directory -Force "$ENV:TMP\powershell-pulp"
       $DownloadPath = "$ENV:TMP\powershell-pulp\" + (Split-Path -Path $Url -Leaf)
       Invoke-WebRequest -Uri $Url -OutFile $DownloadPath
    }
    # Upload each file and record uploadId, fileName, fileSize in array of
    # hashes for later use
    $uploadHashes = @()
    if ($DownloadPath) {
      $files = Get-ChildItem $DownloadPath
    } else {
      $files = Get-ChildItem $Path
    }
    foreach ($file in $files) {
      # Get upload id
      $uri = "/pulp/api/v2/content/uploads/"
      $response = Invoke-PulpRestMethod -Server $Server -Port $Port `
                  -Protocol $Protocol `
                  -AuthenticationMethod $AuthenticationMethod -Uri $uri `
                  -Method Post
      $uploadId = $response.upload_id
      $uploadRef = $response._href
      # Upload file (in chunks if bigger than 1MB)
      $fileName = [string]$file
      $shortFileName = Split-Path $fileName -leaf -resolve
      $chunkSize=1048576
      $fileSize = (get-item $fileName).length
      $uploadHashes += ,@{'uploadId' = $uploadId; 'fileName' = $fileName;
        'shortFileName' = $shortFileName; 'fileSize' = $fileSize}
      # If big file, upload in chunks appending offset to URL
      if ($fileSize -gt $chunksize) {
        $uri = $uploadRef #+ "0/"

        $fileStream = [System.IO.File]::OpenRead($file)
        $chunk = New-Object byte[] $chunkSize
        $offset = 0
        while( $bytesRead = $fileStream.Read($chunk,0,$chunkSize) ){
          $thisUpload = New-Object byte[] $bytesRead
          $thisUpload = [byte[]]($chunk[0..($bytesRead - 1)])
          $progressPreference = 'silentlyContinue'
          $response = Invoke-PulpRestMethod -Server $Server -Port $Port `
                      -Protocol $Protocol `
                      -AuthenticationMethod $AuthenticationMethod `
                      -Uri "${uri}${offset}/" -Method Put `
                      -ContentType "application/data" -Body $thisUpload
          $progressPreference = 'Continue'
          $offset += $chunkSize
          if (($offset / $fileSize*100) -le 100){
            $percentComplete = ($offset / $fileSize*100)
          }
          else {
            $percentComplete = 100
          }
          Write-Progress -Activity `
            "Uploading ${shortFileName} to ${Server}" `
            -status "Uploaded $offset bytes" `
            -percentComplete $percentComplete
        }
        $fileStream.Close()
      # If small file upload the whole thing in one go
      } else {
        $uri = $uploadRef + "0/"
        $response = Invoke-PulpRestMethod -Server $Server -Port $Port `
                    -Protocol $Protocol `
                    -AuthenticationMethod $AuthenticationMethod -Uri $uri `
                    -InFile $fileName -Method Put
      }
    }
    $pipelineCount = 0
    $firstRepoId = ''
  }
  Process {
    If ($TargetRepo) { # Object-based parameter
      $TargetRepoId = $TargetRepo | Select-Object -ExpandProperty id
    }
    elseif ($_) {
    #else {
      $TargetRepoId = $_
    }
    $repos = Get-PulpRepo -Server $Server -Port $Port -Protocol $Protocol `
             -AuthenticationMethod $AuthenticationMethod -Id $TargetRepoId  `
             -Type $Type
    # Import/copy each file into each repo using uploadhashes recorded earlier
    $repocount = 0
    foreach ($repoObject in $repos) {
      $addId = $repoObject.id
      foreach ($uploadHash in $uploadHashes) {
        $uploadId = $uploadHash.uploadId
        $fileName = $uploadHash.fileName
        $shortFileName = $uploadHash.shortFileName
        $fileSize = $uploadHash.fileSize
        # If this is the first repo we import using upload ID...
        if (($repocount -eq 0) -and ($pipelineCount -eq 0)) {
          $firstRepoId = $addId
          # Metadata for RPM upload
          if ($unitType -eq 'rpm') {
            $unitKey = '{}'
            $unitMetaData = '{}'
          }
          # Metadata for Puppet module upload
          elseif ($unitType -eq 'puppet_module') {
            $unitKey = '{}'
            $unitMetaData = '{}'
          }
          # Metadata for other uploads (inc ISO)
          else {
            $checksum = ((Get-FileHash -Path $fileName `
                          -Algorithm SHA256).Hash).ToLower()
            $unitKey =  '{"checksum": "' + $checksum + '", "name": "' +
                          $shortFileName + '", "size": ' + $fileSize + '}'
            $unitMetaData = '{}'
          }
          $uri = "/pulp/api/v2/repositories/${addId}/actions/import_upload/"
          $body = '{"override_config": {}, "unit_type_id": "' + $unitType +'", ' +
                  '"upload_id": "' + $uploadId + '", "unit_key": ' + $unitKey +
                  ', "unit_metadata": '+ $unitMetadata  +'}'
          Invoke-PulpRestMethod -Server $Server -Port $Port `
                                -Protocol $Protocol `
                                -AuthenticationMethod $AuthenticationMethod `
                                -Uri $uri -Body $body -Method Post
          Start-Sleep -s 5
        }
        # ...otherwise we copy from the first repo
        else {
          # Horrible hack to get puppet module name from file name
          If ($unitType -eq 'puppet_module') {
            $splitName = ($shortFileName -Split '.')
            $shortFileName = $split[0..($split.Length-3)] -join '.'
          }
          Get-PulpContentUnit -Server $Server -Port $Port -Protocol $Protocol `
                              -AuthenticationMethod $AuthenticationMethod `
                              -RepoId $firstRepoId -Name $shortFileName `
                              -Type $Type |
          Copy-PulpContentUnit -Server $Server -Port $Port -Protocol $Protocol `
                               -AuthenticationMethod $AuthenticationMethod `
                               -TargetRepoId $addId -Type $Type
        }
      }
      # Publish changes
      If (!$NoPublish) {
        Publish-PulpRepo -Server $Server -Port $Port -Protocol $Protocol `
                         -AuthenticationMethod $AuthenticationMethod `
                         -Id $addId -Type $Type
      }
      $repocount += 1
    }
    $pipelineCount += 1
  }
  End {
    # Delete downloaded file
    If ($DownloadPath) {
      Remove-Item -Recurse -Force $DownloadPath
    }
  }
}