Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapshot for standalone planner #378

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

pranavgore09
Copy link

Added a new groovy script that will deploy snapshot and report the route URL on the PR.
Similar to deployOpenShiftSnapshot

This is being consumed in fabric8-ui/fabric8-planner#2426

body()

def yaml
def openShiftProject = config.openShiftProject
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Why not just use config.openShiftProject instead of using an additional local variable?
  2. Since config is set to empty dictionary in line 7, isnt config.openShiftProject going to be empty here always?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I have used several times later in the code, instead of reading every time from the map I thought local var is good. Not sure though.
  2. .delegate does kind of magic, it will export values passed to function and keep filling up the empty config with provided values if I get it right.

def originalImageName = config.originalImageName
def newImageName = config.newImageName
def deploymentName = config.githubRepo
def providerLabel = config.providerLabel ?: 'fabric8'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All local variables except this would be null. Maybe you forgot a config param in the function signature?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confuses me as well, and follows what is done in https://github.com/fabric8io/fabric8-pipeline-library/blob/master/vars/deployOpenShiftSnapshot.groovy#L11 Is there some magic involved?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaseemabid wonder why you thought all local variables would be null? wouldn't body() initialise these?

Copy link
Contributor

@sthaha sthaha Feb 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pranavgore09 @jaseemabid hopefully this may make sense to you ...

class Body {

  def closure =  {
    println delegate
    println "closure: foo: ${foo}"
    foo = 'barrrr'
    bar = 'baaazzz'
  }
}


def config = [ foo: "bar"]
def obj = new Body()
def body = obj.closure

body.delegate = config

println "main: foo: ${config.foo}"
println "main: bar: ${config.bar}"

body()

println "main: foo: ${config.foo}"
println "main: bar: ${config.bar}"

Output:

main: foo: bar                
main: bar: null               
class delegate                
closure: foo: bar             
main: foo: barrrr             
main: bar: baaazzz 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just in case you are wondering where I got this idea from :) - https://stackoverflow.com/a/23450944

def flow = new io.fabric8.Fabric8Commands()
def utils = new io.fabric8.Utils()

openShiftProject = openShiftProject + '-' + utils.getRepoName()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define the variable here, avoid that mutation

Copy link
Author

@pranavgore09 pranavgore09 Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes done, now only one declaration in a869abe

}
// cant use writeFile as we have long filename errors
sh "echo '${yaml}' > snapshot.yml"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is probably a groovy function called write, so that we dont have to spawn a subshell here. There must be something similar to write('snapshot.yml', yaml)

Copy link
Author

@pranavgore09 pranavgore09 Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kept is as it is, but added the error that I faced in a comment above it a869abe#diff-e29e1891af9b97dd7f7137d912b468acR39

def utils = new io.fabric8.Utils()

openShiftProject = openShiftProject + '-' + utils.getRepoName()
container('clients') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spawning the clients container just to get oc binary seems a bit too much. Should probably add the 'oc' binary to the jenkins builder image and scrap this. Need not be part of this PR obviously, but something that needs a look. WDTY @rupalibehera @chmouel @sthaha

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what you meant by jenkins builder image; not an area I know. is it the jenkins master image?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sthaha Yes. I meant master. Looks like we bring in yet another repository and image and container just for the oc binary from https://github.com/fabric8io-images/builder-clients, which is what I was hoping to get rid of.

return true
} catch (err) {
echo "waiting for ${deploymentName} to be ready..."
return false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this waitUntill a tight loop? Do you think there should be a sleep if it fails? Is that inbuilt? If we add a sleep before the return false, we can remove the sleep 10 above?

Copy link
Contributor

@sthaha sthaha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice patch! Looks good to me, some minor comments thou.

body()

def yaml
def openShiftProject = config.openShiftProject
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about def openshiftProject = config.openshiftProject + '-' + utils.getRepoName()
so that this variable isn't overwritten in line 24?

Copy link
Author

@pranavgore09 pranavgore09 Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! done in a869abe

def flow = new io.fabric8.Fabric8Commands()
def utils = new io.fabric8.Utils()

openShiftProject = openShiftProject + '-' + utils.getRepoName()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, keeping variables as immutable as possible makes it easy to reason with the code. Here openshiftProject isn't acting like an accumulator (sum, product etc...) so we can keep it immutable like mentioned in the comment above

Copy link
Author

@pranavgore09 pranavgore09 Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 fixed a869abe

error 'Change author is not a collaborator on the project, aborting build until we support the [test] comment'
}

yaml = flow.getUrlAsString(openShiftTemplate)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same pattern here, made me think that yaml is getting overwritten in the line below. how about:

def url = flow.getUrlAsString(openshiftTemplate)
def originalImage = "- image: ${...}"
def newImage = "- image: ${...}"
yaml = Pattern.compiler(originalImage).matcher(url).replaceFirst(newImage)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, fixed.

sh "echo '${yaml}' > snapshot.yml"

container('clients') {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could convert this into a reusable method switchProject(project)

@jaseemabid
Copy link
Contributor

@pranavgore09 Several comments inline. AFAIK, it fundamentally boils down to a

wget openShiftTemplate > snapshot.yml 
oc apply -f snapshot.yml

I guess a straightforward shell script would look a lot saner than so many levels of indirection caused by this library. The patch looks fine & it seems to fit in with the rest of the code. LGTM except the inline comments.

Added new groovy script for building and deploying plannerUI standalone
snapshot in CI.
@pranavgore09
Copy link
Author

@jaseemabid @sthaha I have removed container(clients) where it was not required and variables are not modified after assignment.
please review once! thanks.

def originalImage = "- image: ${originalImageName}:(.*)"
def newImage = "- image: ${newImageName}"
def compiledYaml = Pattern.compile(originalImage).matcher(yaml).replaceFirst(newImage)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pranavgore09 Its slightly odd that we use string matching and regular expressions to get data out of a structured data interchange format. I would have expected to see something like this.

def yaml = Yaml.parse(flow.getUrlAsString(openShiftTemplateURL))
yaml.services[1].image = config.newImage  // Whatever the real path is
def snapshot = yaml.toString()
// Remove the check below, because that wont fail now. 

I'm OK with this code, this might be written this way because of other nuances like groovy sandbox or something which we don't know.

Point being, this feels like a very poor groovy implementation of

wget openShiftTemplate > snapshot.yml
sed -i -e 's/oldImage/newImage/g' snapshot.yml

and that feels really odd.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It indeed has a method to parse yaml but @jaseemabid mentioned I feel this is consistent with the existing implementation so lets go ahead with this and fix both later as a separate issue.

Copy link
Contributor

@sthaha sthaha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

def originalImageName = config.originalImageName
def newImageName = config.newImageName
def deploymentName = config.githubRepo
def providerLabel = config.providerLabel ?: 'fabric8'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaseemabid wonder why you thought all local variables would be null? wouldn't body() initialise these?

def originalImage = "- image: ${originalImageName}:(.*)"
def newImage = "- image: ${newImageName}"
def compiledYaml = Pattern.compile(originalImage).matcher(yaml).replaceFirst(newImage)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It indeed has a method to parse yaml but @jaseemabid mentioned I feel this is consistent with the existing implementation so lets go ahead with this and fix both later as a separate issue.

@jaseemabid
Copy link
Contributor

LGTM. Merge 👍

@bartoszmajsak
Copy link
Contributor

Just a general thought I wanted to share - this kind of functions should not belong to the "library" as they are very specific to particular projects. That makes them unshareable essentially. So either we could decompose it to more "generic purpose" functions and reuse from within Planner Jenkinsfile or maybe create it's own "planner-pipeline-library" with those bits instead? (I believe one can have more than one @Library reference in the Jenkinsfile itsefl - see here for more details https://jenkins.io/doc/book/pipeline/shared-libraries/.

/cc @pradeepto @joshuawilson

@joshuawilson
Copy link
Contributor

I have questioned this approach of one-off functions since we started using it. I don't know how we can move away from it quickly. So we might just accept this but work toward a better solution.

@bartoszmajsak
Copy link
Contributor

@joshuawilson timebox it for 1 day for someone in your team and try? I think it's easily done based on the guide I shared above.

@pranavgore09
Copy link
Author

pranavgore09 commented Feb 15, 2018

thanks, @bartoszmajsak @joshuawilson for taking a look, but when I started working on this, my intention was to deploy snapshot for the standalone planner, over a period of time it changed to a greater extent and as of now that change does not have any static things in it, any specific setup inside. Except the name of the file itself.

essentially it deploys application given in openshiftTemplate. here

The only line is regex matcher that seems to be static, but IMO that is fine.
WDYT @jaseemabid @sthaha @bartoszmajsak @joshuawilson about changing its name to something more meaningful for a library

@bartoszmajsak
Copy link
Contributor

Thanks for explanation @pranavgore09, makes sense :) Nice work! My comment was a more a general statement.

Maybe in this given case we only need to rename the function then. But we do have a lot of other fabric8..Deploy... functions which are project specific - this needs to be addressed as part of openshiftio/openshift.io#2243.

@jaseemabid
Copy link
Contributor

@bartoszmajsak @joshuawilson There is a whole lot of project specific code in the library and I think we all agree that it doesn't make much sense.

We will need to take a look at it as a whole and trim down a lot. For example, #372

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants