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

[JENKINS-59048] Export the spotBlockReservationDurationStr constructor parameter for JCasc #443

Merged
merged 14 commits into from
Apr 26, 2020

Conversation

multani
Copy link
Contributor

@multani multani commented Mar 14, 2020

The Jenkins "Configuration as Code" plugin raises an error while trying
to export the spotBlockReservationDurationStr attribute from the
configuration, as this constructor attribute is not exposed in the
SpotConfiguration class.

Fix: JENKINS-59048

The Jenkins "Configuration as Code" plugin raises an error while trying
to export the `spotBlockReservationDurationStr` attribute from the
configuration, as this constructor attribute is not exposed in the
`SpotConfiguration` class.

Fix: JENKINS-59048
@res0nance
Copy link
Contributor

I've requested a review from the jcasc guys because I'm not sure if this is the right fix

@res0nance res0nance changed the title Export the spotBlockReservationDurationStr constructor parameter for th [JENKINS-59048] Export the spotBlockReservationDurationStr constructor parameter for th Mar 16, 2020
@res0nance res0nance changed the title [JENKINS-59048] Export the spotBlockReservationDurationStr constructor parameter for th [JENKINS-59048] Export the spotBlockReservationDurationStr constructor parameter for JCasc Mar 16, 2020
@jetersen
Copy link
Member

jetersen commented Mar 16, 2020

Okay after looking into it my recommendation still stands.
Make SpotConfig describable.
Add a jelly config for it.
Change

<f:optionalBlock name="spotConfig" title="Use Spot Instance" checked="${instance.spotConfig != null}">
<f:entry title="${%Fallback to on-demand instances}" >
<f:checkbox field="fallbackToOndemand" checked="${instance.spotConfig.fallbackToOndemand}" />
</f:entry>
<f:optionalBlock name="useBidPrice" title="Set bid price" inline="true" checked="${h.defaultToTrue(instance.spotConfig.useBidPrice)}">
<f:validateButton title="${%Check Current Spot Price}" progress="${%Checking...}" method="currentSpotPrice" with="useInstanceProfileForCredentials,credentialsId,region,type,zone,roleArn,roleSessionName,ami" />
<f:entry title="${%Spot Max Bid Price}" field="spotMaxBidPrice">
<f:textbox />
</f:entry>
</f:optionalBlock>
<f:entry title="${%Spot Block Reservation Duration}" field="spotBlockReservationDurationStr">
<f:textbox />
</f:entry>
</f:optionalBlock>

to use a

<f:optionalProperty title="${%Spot configuration}" field="spotConfig"/>

in the newly created spotConfig jelly
you can update it to

    <f:entry title="${%Fallback to on-demand instances}" >
      <f:checkbox field="fallbackToOndemand" checked="${instance.spotConfig.fallbackToOndemand}" />
    </f:entry>
    <f:optionalBlock name="useBidPrice" title="Set bid price" inline="true" checked="${h.defaultToTrue(instance.spotConfig.useBidPrice)}">
      <f:validateButton title="${%Check Current Spot Price}" progress="${%Checking...}" method="currentSpotPrice" with="useInstanceProfileForCredentials,credentialsId,region,type,zone,roleArn,roleSessionName,ami" />
      <f:entry title="${%Spot Max Bid Price}" field="spotMaxBidPrice">
        <f:textbox />
      </f:entry>
    </f:optionalBlock>
    
    <f:entry title="${%Spot Block Reservation Duration}" field="spotBlockReservationDuration">
      <f:number />
    </f:entry>

@multani
Copy link
Contributor Author

multani commented Mar 16, 2020

Thanks @res0nance, @timja and @jetersen for the review and suggestions!

I'm still new to Jenkins plugin development, so I'll try to dig a bit more. If I sum up:

  • I'll deprecate the constructor to correctly use mandatory and optional fields, adding getters/setters for optional fields (I need to dig into that)
  • I'll update the Jelly, extract the SpotConfig and change it to use numbers instead of strings 👍
  • Update the tests as well (I missed that!)

@multani
Copy link
Contributor Author

multani commented Mar 16, 2020

So, I think I addressed most of the comments:

  • The previous constructor has been deprecated in favor of one with only the mandatory parameter.

    I went with only useBidPrice as the mandatory argument, as it drives the decision to use "spot instances" or "on-demand instances" if it's set or not...

    (TBH, the whole functionality from this class is a bit weird, as to use AWS EC2 Spot Instances, a bit price has to be set, but the UI allows to select spot instances without a bid price, which requests on-demand instances.
    Also, the bid price should be number, not a string, etc.

    Anyway, I put all these concerns aside as it's not really the purpose of the patch.)

    • DataBoundDescriptor should be better implemented now (AFAIU?)

    • I had to remove the final from the fields for them to be settable via the DataBoundSetter, I could also make them private (let me know, that will increase a bit the patch though.)

  • I move the spot configuration in a dedicated Jelly file.

  • I upgraded the current test to also test the loading/dumping of the spot
    configuration.

This changes a few things though:

  • "Spot Block Reservation Duration" is now always set to 0 by default, which is an acceptable and should have the same behavior as the empty string before.

  • Dumping the configuration via JCasC doesn't dump the default parameters: if "Spot Block Reservation Duration" and "Fallback to on-demand instances" have the default values, then they don't appear in the YAML file.

    I'm not sure about this one, as if the default values are changing later on, loading the as-of-today configuration in the then-plugin will produce a different final configuration.

There's still a test failing in testSpotConfigWithFallback: orig.spotConfig.useBidPrice is false while received.spotConfig.useBidPrice is true... I haven't dig into that one yet.

Copy link
Member

@jetersen jetersen left a comment

Choose a reason for hiding this comment

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

One minor nit pick! Otherwise excellent job! 😍

src/main/java/hudson/plugins/ec2/SpotConfiguration.java Outdated Show resolved Hide resolved
<f:checkbox field="fallbackToOndemand" checked="${instance.spotConfig.fallbackToOndemand}" />
</f:entry>

<f:optionalBlock name="useBidPrice" title="Set bid price" inline="true" checked="${h.defaultToTrue(instance.spotConfig.useBidPrice)}">
Copy link
Member

Choose a reason for hiding this comment

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

Not sure this optional block makes sense... however I do not use the plugin.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it doesn't really make sense to me, as I explained above:

  • Either you selected "I want to request a Spot instance" and you need to specify a price (this is mandatory on the AWS' side)
  • Or, you don't want to request Spot instances, in which case the spotConfig block is just not set.

I could make that change here, but I think it goes a bit out of scope of the initial issue, and it will require more change in the code to reflect that new "logic" (it's a bit convoluted at the moment IMO).
So, I'd prefer to stay at the same feature level for that PR :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure this optional block makes sense...

Actually, why do you think it doesn't make sense?
The failing test is actually on that attribute, so may be I misunderstood your comment :)

@jetersen
Copy link
Member

JCasC by design does not print default values when exporting.
If default's are changed it's because the plugin maintainer wanted that. So JCasC should not interfere.

I may be able to look into the test failure tomorrow if needed.

Copy link
Member

@timja timja left a comment

Choose a reason for hiding this comment

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

I haven’t checked the UI of how this looks, but the jcasc side of it looks a lot better, and having the test updates greatly increases the confidence, for now and future changes

src/test/resources/hudson/plugins/ec2/UnixData.yml Outdated Show resolved Hide resolved
@timja
Copy link
Member

timja commented Mar 17, 2020

RE: making the fields private, that’s a breaking change and not recommended, the usual approach for that is creating a new field and migrating the old data.

Not worth it here imo

multani and others added 2 commits March 17, 2020 08:21
These fields are already defaulting to these values

Co-Authored-By: Joseph Petersen <josephp90@gmail.com>
@multani
Copy link
Contributor Author

multani commented Mar 21, 2020

The test failure is actually a genuine bug: I tried manually to save a config where "Set bid price" was not checked, and it appears again as "checked" when reloading the page.

@multani
Copy link
Contributor Author

multani commented Mar 21, 2020

Found the issue ( 🤞 ): I forgot to remove the access to the spotConfig attribute when I moved the SpotConfiguration jelly file to a dedicated file.

Copy link
Member

@jetersen jetersen left a comment

Choose a reason for hiding this comment

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

Definitely a step in the right direction, good job @multani 🙇‍♂️

@multani multani requested review from timja and res0nance March 21, 2020 14:36
@multani
Copy link
Contributor Author

multani commented Mar 21, 2020

Arf, apparently, the "Check Current Spot Price" button doesn't work anymore ... 🤦‍♂️

The button moved along the SpotConfiguration Jelly but not the attached
action.

I also moved the non-SlaveTemplate related functions used as static methods
in CloudHelper, as they are being used in several places.
@multani
Copy link
Contributor Author

multani commented Mar 25, 2020

I don't think the test failure is related to my branch, is it possible to restart the build?

@timja
Copy link
Member

timja commented Mar 25, 2020

I don't think the test failure is related to my branch, is it possible to restart the build?

if you close and reopen the PR it'll trigger it again

@multani multani closed this Mar 25, 2020
@multani multani reopened this Mar 25, 2020
@multani
Copy link
Contributor Author

multani commented Apr 9, 2020

Hi, is there anything else that I must do on this pull request?
AIFAK, the tests are now passing and I (should have!) addressed all the issues :)

@jetersen
Copy link
Member

jetersen commented Apr 9, 2020

it's up to the maintainers for the plugin to review and merge 😅 I was only pinged to review because of the JCasC side of things.

@res0nance res0nance requested review from jvz and varyvol April 15, 2020 01:34
@res0nance res0nance closed this Apr 15, 2020
@res0nance res0nance reopened this Apr 15, 2020
@thoulen thoulen merged commit e4d2a5d into jenkinsci:master Apr 26, 2020
@multani
Copy link
Contributor Author

multani commented Apr 26, 2020

@thoulen Thanks a lot for the merge!

I wanted to updated JENKINS-59048 to reflect the changes, but I keep getting HTTP 403 errors whatever I'm trying to do (watch the ticket, comment, etc.) 🤷‍♂️

@timja
Copy link
Member

timja commented Apr 26, 2020

@multani update it on https://issues.jenkins-ci.org, the domain you're on doesn't work

@multani multani deleted the jenkins-59048 branch April 26, 2020 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
6 participants