/*
* Licensed Materials - Property of IBM* and/or HCL**
* UrbanCode Deploy
* UrbanCode Build
* UrbanCode Release
* AnthillPro
* (c) Copyright IBM Corporation 2011, 2017. All Rights Reserved.
* (c) Copyright HCL Technologies Ltd. 2023. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*
* * Trademark of International Business Machines
* ** Trademark of HCL Technologies Limited
*/

import com.urbancode.air.AirPluginTool
import com.urbancode.air.plugin.argocd.ArgoCDHelper
import com.urbancode.air.plugin.argocd.Inventory
import org.apache.log4j.Level
import org.apache.log4j.Logger

import groovy.yaml.YamlSlurper

// Get step properties
def apTool   = new AirPluginTool(args[0], args[1])
def inProps  = apTool.getStepProperties()

/* We acquire the specified log4j level from the input properties and set the root logger level.
 * This will set the logger level for all loggers retrieved in this step.
 * If the logger level specified is invalid, we default to INFO.
 */
String logLevel = inProps['loggerLevel']
Logger.getRootLogger().setLevel(Level.toLevel(logLevel, Level.INFO))
Logger logger = Logger.getLogger(getClass())

String application = inProps['application']?.trim()
String flags       = inProps['flags']?.trim();
String cmdpath     = inProps['cmdpath']?.trim();

// Set up helper
File workDir = new File(".").canonicalFile
ArgoCDHelper acdh = new ArgoCDHelper(workDir, cmdpath)

/*
 * Need to check that we were given application name(s), label selector,
 * resource list, or project name(s)
 */
/*
if (!application && !flags.contains("-l") && !flags.contains("--label") && !flags.contains("--selector") && !flags.contains("--resources" && !flags.contains("--project") {
    println('[Error] The step requires application name(s), label selector(s), resources list, or project name(s) be given')
    System.exit(1)
}
*/

// Sync the application
def args = []
args << 'app'
args << 'sync'

if (application) {
    args << application
}

String soutSync
acdh.setFlags(args, flags)
acdh.runCommand("[Action] Syncing application(s)...", args) { Process proc ->
    def (String sout, String serr) = acdh.captureCommand(proc)
    println ('[Stderr output]')
    println (serr)
    println ('[Stdout output]')
    println (sout)
    soutSync = sout
}

// Now that the application has been synced, gather info about the currently
// deployed component(s) and update inventory.
// We need to look at the output of the 'argocd app sync...' command above to
// get a list of all the applications that were just sync'ed.  For each
// application, we need to get the manifests of the resources and look through
// them for image specs.

// Parse list of applications from 'argocd app sync...' command stdout
def applications = []
soutSync.eachLine( { String line ->
  if (line.matches(~/^Name:.*$/)) {
    def parts = line.split("\s+")
    applications.add(parts[1])
  }
})

// For each application, execute 'argocd app manifests...' to get kubernetes
// resources associated with that application.  We look for image specs
// contained in those resources to determine what needs to be updated in
// the environment inventory.
def imageSpecs = []
for (app in applications) {
  ArgoCDHelper acdhM = new ArgoCDHelper(workDir, cmdpath)
  String globalFlags = acdhM.getGlobalArgs(flags)
  args = []
  args << 'app'
  args << 'manifests'
  args << app
  args << '--source=live'
  acdhM.setFlags(args, globalFlags)

  acdhM.runCommand("[Action] Getting live manifests for application", args) { Process procM ->
      def (String soutM, String serrM) = acdhM.captureCommand(procM)
      /*
       * This info would be helpful for debugging
      println ('[Stderr output]')
      println (serrM)
      println ('[Stdout output]')
      println (soutM)
      */

      def manifests = soutM.split('---').findAll().collect {
        new YamlSlurper().parseText(it)
      }

      for (manifest in manifests) {
        switch (manifest.kind) {
          case "Deployment":
          case "Statefulset":
          case "ReplicaSet":
          case "ReplicationController":
          case "DaemonSet":
          case "Job":
          case "DeploymentConfig":  //OpenShift specific resource
            for (container in manifest.spec.template.spec.containers) {
              imageSpecs.add(container.image)
            }
            break
          case "CronJob":
            for (container in manifest.spec.jobTemplate.spec.template.spec.containers) {
              imageSpecs.add(container.image)
            }
            break
          }
      }
  }
}

printf("Found images: %s\n", imageSpecs.toString())

Inventory inv = new Inventory(apTool)
inv.update(imageSpecs as String[]);
