Enable manual provisioning for windows machines. #6523

Merged
merged 4 commits into from Jan 24, 2017

Conversation

Projects
None yet
6 participants
Contributor

hoenirvili commented Nov 1, 2016

This patch contains:

  • make userdata run through winrm
  • install x509 certs for winrm secure client connections into windows
    machines
  • generate x509 client certificate when running a juju command if the
    cert dosen't exist.
  • powershell scripts for init, for gathering info, for creating config
    files, etc.
  • support for windows 2016 nano detection
  • auto detection for CA verification in winrm connections

Ignore unit tests for now, I will write them after we all agree on the api.

Contributor

hoenirvili commented Nov 1, 2016

This patch depends on this patch.

juju/utils#249

Owner

mitechie commented Nov 28, 2016

@hoenirvili can you please check the conflicts?

@axw and @natefinch can you please take a peek at this PR?

Contributor

hoenirvili commented Nov 28, 2016

@mitechie fixed !

Contributor

natefinch commented Nov 28, 2016

!!build!!

Member

anastasiamac commented Nov 29, 2016

!!build!!

Contributor

hoenirvili commented Nov 29, 2016

!!build!!

Contributor

hoenirvili commented Dec 2, 2016

!!build!!

Contributor

hoenirvili commented Dec 13, 2016

@natefinch what are your thoughts on this patch?

Mostly ok, but needs some cleanup in the given spots.

Major point is to avoid using JujuConnSuite in the tests. Please test as much as you can without using JujuConnSuite and then write a CI test to actually manually adding a real windows machine.

+
+ caCert := cert.CACert()
+ if caCert == nil {
+ logger.Infof("Skipping winrm CA validation")
@natefinch

natefinch Jan 5, 2017

Contributor

Can you add to the log message why we're skipping it?

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Yes, sure 👍 Fixed !

+ if caCert == nil {
+ logger.Infof("Skipping winrm CA validation")
+ cfg.Insecure = true
+
@natefinch

natefinch Jan 5, 2017

Contributor

remove blank line

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

+package winrmprovisioner
+
+var (
+ WinDetectHardware = detectHardware
@natefinch

natefinch Jan 5, 2017

Contributor

this doesn't seem to be used anywhere

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

+ }()
+
+ if err = InitAdministratorUser(&args); err != nil {
+ return machineId, errors.Annotatef(err,
@natefinch

natefinch Jan 5, 2017

Contributor

probably clearer to return "" rather than machineId, just so it's clear you're returning an empty string here

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

Have you pushed your fixes? I'm pretty sure Nate meant to use a string literal of "" here (i.e. return "", ...).

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+
+ if err = InitAdministratorUser(&args); err != nil {
+ return machineId, errors.Annotatef(err,
+ "Cannot provision machine beacuse no WinRM http/https standard",
@natefinch

natefinch Jan 5, 2017

Contributor

this error is not going to turn out the way you expect, and this will likely fail go vet. The first string is the format string, the rest of the strings are the args to the format string. The easiest fix is to replace the comma on this line with a +, so you're just concatenating the two lines (add a space at the end of this line, too)

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

fixed !

+ })
+
+ if err != nil {
+ logger.Errorf("Cannot obtain provisioning script")
@natefinch

natefinch Jan 5, 2017

Contributor

this error will handled at a higher level, so the log message here is probably redundant

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

+)
+
+type provisionerSuite struct {
+ testing.JujuConnSuite
@natefinch

natefinch Jan 5, 2017

Contributor

We're trying to avoid using JujuConnSuite for new tests. It's too slow, and requires too much hackery to make work.

I think we can test the majority of the code via unit tests, mocking out specific pieces, and then write a full CI test to do real provisioning with a real windows machine to test the end to end bits.

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ },
+
+ fakeRun: func(cmd string, stdout, stderr io.Writer) error {
+ c.Assert((len(cmd) > 0), gc.Equals, true)
@natefinch

natefinch Jan 5, 2017

Contributor

more specific check here please

+`
+
+// detectHardware is a powershell script that determines the following:
+// - the processor architecture
@natefinch

natefinch Jan 5, 2017

Contributor

the formatting on this comment is a little weird. Can you clean it up some?

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Why this is wierd? I think this comes to personal preference. I didn't come with a better way of explaining this powershell script in another manner. Also in my oppinion it's a good comment with main bullet points and very structured(all points explained).
If have a different opinion please elaborate more.

+// the Administrator user using the secure client
+// only if this is false then this will make a new attempt with the unsecure http client.
+func InitAdministratorUser(args *manual.ProvisionMachineArgs) error {
+ logger.Infof("Trying https client as user %s on %s", args.Host, args.User)
@natefinch

natefinch Jan 5, 2017

Contributor

I think this is more a debug level thing. If everything works, there's no need to mention anything to the user. Plus, if we keep everything in this function at debug level, then it'll provide a more consistent behavior for the person looking at the logs. Right now it's kind of random which are debug and which are info.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

So what are you suggesting? To replace all logger.Infof with logger.Debuf ?

+// we are doing this instead of one big script because winrm supports
+// just 8192 length commands. We know we have an amount of prefixed scripts
+// that we want to bind for the init process so create an array of scripts
+func bindInitScripts(pass string, keys *winrm.X509) ([3]string, error) {
@natefinch

natefinch Jan 5, 2017

Contributor

There's no real reason to use an array as the return value rather than a slice. If we decide we need to return 4 scripts instead of 3, the calling code shouldn't care, I presume it just ranges through the results anyway.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Yeah it ranges through the result. But I choosed a simple array over slice for many reasons.
Why should I assume or let the compiler decide if the space is stored on heap or stack?
It's more a memory efficient way to just make a simple array on stack and use it. It's not like the array needs to get bigger or modify it any time soon.
Why should I clutter the code with append ? Or use unnecessary call to make at the start ?(And make it's not 100% it will make the decision to make it on heap)
Using a simple array I inform the caller that he/she will deal with a constant number of scripts.

@axw

axw Jan 23, 2017

Member

This code isn't on any hot path, so how the memory is allocated is not important. Maintainability is more important in general. Please use a slice; the caller should not care how many elements there are. As such, exposing it is creating too tight a dependency from callers to the implementation details.

(Also, FWIW: you can preallocate a slice and assign by index just as you do below. The compiler might even be smart enough to elide bounds checking, but even if it's not, it's going to have no noticeable impact on the runtime of the program.)

+ )
+
+ if len(pass) == 0 {
+ return scripts, fmt.Errorf("The password is empty, provide a valid password to enable https interactions")
@natefinch

natefinch Jan 5, 2017

Contributor

you should use errors.New here, which records stack information.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

+
+ scripts[0], err = shell.NewPSEncodedCommand(setFiles)
+ if err != nil {
+ return scripts, err
@natefinch

natefinch Jan 5, 2017

Contributor

in cases where there's an error, it's more appropriate to return nil, err, so we're not returning potentially partially formed data in the array of scripts.

In addition, you should use errors.Trace(err) so we keep stack info on the error.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+
+ provisioned, err := checkProvisioned(hostname, cli)
+ if err != nil {
+ err = fmt.Errorf("error checking is provisioned: %v", err)
@natefinch

natefinch Jan 5, 2017

Contributor

please use errors.Annotate here and below

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ // if it isn't one that the environment provider knows about.
+
+ instanceId := instance.Id(manual.ManualInstancePrefix + hostname)
+ nonce := fmt.Sprintf("%s:%s", instanceId, uuid.String())
@natefinch

natefinch Jan 5, 2017

Contributor

just FYI, you don't need the .String() on uuid. fmt.Sprintf will look for a .String() method if you're passing something into a %s format value.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+// checkProvisioned checks if the machine is already provisioned or not.
+// if it's already provisioned it will return true
+func checkProvisioned(host string, cli manual.WinrmClientAPI) (bool, error) {
+ logger.Infof("Checking if %s windows machine is already provisioned", host)
@natefinch

natefinch Jan 5, 2017

Contributor

this seems like it should be trace level

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

+
+ provisioned := strings.Contains(stdout.String(), "Yes")
+ if stderr.Len() != 0 {
+ err = fmt.Errorf("%v (%v)", err, strings.TrimSpace(stderr.String()))
@natefinch

natefinch Jan 5, 2017

Contributor

please use errors.Annotatef here

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

+// - info[2] the series of the machine
+// - info[3] the number of cores that the machine has
+// It returns nil if it parsed successfully.
+func initHC(hc *instance.HardwareCharacteristics, info []string) error {
@natefinch

natefinch Jan 5, 2017

Contributor

it's more idiomatic to simply return a new hardware characteristics value, rather than passing in a pointer to be filled out.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

I think it's fine this way, the name implies that given *hc it will initialize(modify) after the call.

+ return errors.Annotatef(err, "Can't parse mem number of the windows machine")
+ }
+ hc.Mem = new(uint64)
+ *hc.Mem = mem
@natefinch

natefinch Jan 5, 2017

Contributor

this can just be hc.Mem = &mem and drop the new(uint64) above

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

No, because after we exit the scope the hc.Mem will be nil.

@axw

axw Jan 23, 2017

Member

No, because after we exit the scope the hc.Mem will be nil.

"mem" will be captured by the reference, and will be stored on the heap (assuming hc is also stored on the heap). It's fine (and preferable) to do hc.Mem = &mem.

+ }
+
+ hc.CpuCores = new(uint64)
+ *hc.CpuCores = cores
@natefinch

natefinch Jan 5, 2017

Contributor

hc.CpuCores = &cores

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Check above comm.

+
+ udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg)
+ if err != nil {
+ return "", errors.Annotate(err, "error generating cloud-config")
@natefinch

natefinch Jan 5, 2017

Contributor

ideally you'd make these error messages distinct so it's more obvious which one is causing the problem.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@axw

axw Jan 24, 2017

Member

Please make these errors distinct from one other.

+
+ // this should return to ioctl device error
+ err = winrmprovisioner.InitAdministratorUser(&args)
+ c.Assert(err, gc.NotNil)
@natefinch

natefinch Jan 5, 2017

Contributor

this needs a more specific test that we're returning the right kind of error

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

So what are you proposing? should I move this into a new func TestIotlErrReturn or smth ?

+
+ hc, ser, err := winrmprovisioner.DetectSeriesAndHardwareCharacteristics(winrmListenerAddr, fakeCli)
+ c.Assert(err, gc.IsNil)
+ c.Assert((len(ser) > 0), gc.Equals, true)
@natefinch

natefinch Jan 5, 2017

Contributor

this is extraneous, with the check on line 71

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

You can drop this line as Nate mentions, but FYI for future: you can use c.Assert(ser, gc.Not(gc.HasLen), 0). This preserves the value of ser for the error message.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ c.Assert((len(ser) > 0), gc.Equals, true)
+ c.Assert(hc, gc.NotNil)
+ c.Assert(ser, jc.DeepEquals, series)
+ c.Assert(*hc.Arch, jc.DeepEquals, arch)
@natefinch

natefinch Jan 5, 2017

Contributor

you can just use gc.Equals for strings

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ var stdin, stderr bytes.Buffer
+ fakeCli := &fakeWinRM{
+ fakeRun: func(cmd string, stdout, stderr io.Writer) error {
+ c.Assert((len(cmd) > 0), gc.Equals, true)
@natefinch

natefinch Jan 5, 2017

Contributor

seems like we could do a smarter assert than this

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

juju/home.go
+ return errors.Annotatef(err, "connot load/create x509 client certs for winrm connection")
+ }
+
+ _ = cert.LoadCACert(filepath.Join(base, "winrmcacert.crt"))
@natefinch

natefinch Jan 5, 2017

Contributor

why are you dropping this error?

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

I'm skipping this error because this InitJujuXDGDataHome runs everytime I launch a juju command. So not all commands deal with provisioning or needs that CA cert to work. This is also very "windows specific" and only the juju add-machine benefits from this. So we don't need to annoy the user that he doesn't have a CACert alongside with the client cert and key.
This check is already done in the winrmprovisioner code when the provisioning process starts.

Contributor

hoenirvili commented Jan 11, 2017

@natefinch Could you please take a look at the code and add more recommendations?

Giulitti Salvatore added some commits Dec 5, 2016

This patch contains:
 - make userdata run through winrm
 - install x509 certs for winrm secure client connections into windows
   machines
 - generate x509 client certificate when running a juju command if the
   cert dosen't exist.
 - powershell scripts for init, for gathering info, for creating config
   files, etc.
 - support for windows 2016 nano detection
 - auto detection for CA verification in winrm connections

Signed-off-by: Giulitti Salvatore <sgiulitti@cloudbasesolutions.com>
Add unit tests.
Signed-off-by: Giulitti Salvatore <sgiulitti@cloudbasesolutions.com>

There's a bunch of comments that haven't been addressed, though you have commented saying "Fixed". Please double-check; maybe you didn't push some commits?

apiserver/client/client.go
+ "cannot decide which provisioning script to generate based on this series %q", icfg.Series))
+ }
+
+ switch osSeries {
@axw

axw Jan 23, 2017

Member

this could be simplified to:

getProvisioningScript := sshprovisioner.ProvisioningScript
if osSeries == os.Windows {
    getProvisioningScript = winrmprovisioner.ProvisioningScript
}
result.Script, err = getProvisioningScript(icfg)
if err != nil {
    return result, common.ServerError(errors.Annotate(
        err, "getting provisioning script",
    ))
}
environs/manual/provisioner.go
@@ -50,9 +51,22 @@ type ProvisionMachineArgs struct {
// ubuntu user's ~/.ssh/authorized_keys.
AuthorizedKeys string
+ // WKeys winrm keys that contains, CACert, ClientCert, ClientKey
+ WKeys *winrm.X509
@axw

axw Jan 23, 2017

Member

Can you please expand the W here and below to WinRM. It's not very meaningful out of context

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ }()
+
+ if err = InitAdministratorUser(&args); err != nil {
+ return machineId, errors.Annotatef(err,
@natefinch

natefinch Jan 5, 2017

Contributor

probably clearer to return "" rather than machineId, just so it's clear you're returning an empty string here

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

Have you pushed your fixes? I'm pretty sure Nate meant to use a string literal of "" here (i.e. return "", ...).

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+// we are doing this instead of one big script because winrm supports
+// just 8192 length commands. We know we have an amount of prefixed scripts
+// that we want to bind for the init process so create an array of scripts
+func bindInitScripts(pass string, keys *winrm.X509) ([3]string, error) {
@natefinch

natefinch Jan 5, 2017

Contributor

There's no real reason to use an array as the return value rather than a slice. If we decide we need to return 4 scripts instead of 3, the calling code shouldn't care, I presume it just ranges through the results anyway.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Yeah it ranges through the result. But I choosed a simple array over slice for many reasons.
Why should I assume or let the compiler decide if the space is stored on heap or stack?
It's more a memory efficient way to just make a simple array on stack and use it. It's not like the array needs to get bigger or modify it any time soon.
Why should I clutter the code with append ? Or use unnecessary call to make at the start ?(And make it's not 100% it will make the decision to make it on heap)
Using a simple array I inform the caller that he/she will deal with a constant number of scripts.

@axw

axw Jan 23, 2017

Member

This code isn't on any hot path, so how the memory is allocated is not important. Maintainability is more important in general. Please use a slice; the caller should not care how many elements there are. As such, exposing it is creating too tight a dependency from callers to the implementation details.

(Also, FWIW: you can preallocate a slice and assign by index just as you do below. The compiler might even be smart enough to elide bounds checking, but even if it's not, it's going to have no noticeable impact on the runtime of the program.)

+ return errors.Annotatef(err, "Can't parse mem number of the windows machine")
+ }
+ hc.Mem = new(uint64)
+ *hc.Mem = mem
@natefinch

natefinch Jan 5, 2017

Contributor

this can just be hc.Mem = &mem and drop the new(uint64) above

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

No, because after we exit the scope the hc.Mem will be nil.

@axw

axw Jan 23, 2017

Member

No, because after we exit the scope the hc.Mem will be nil.

"mem" will be captured by the reference, and will be stored on the heap (assuming hc is also stored on the heap). It's fine (and preferable) to do hc.Mem = &mem.

+ input := bytes.NewBufferString(script64) // make new buffer out of script
+ // will make sure to buffer the entire script
+ // in a sequential write fashion first into a script
+ // decouple the provisioning script into little 512 bytes chunks
@axw

axw Jan 23, 2017

Member

s/512/1024/?

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

s/512/1024/?
Updated.

assuming hc is also stored on the heap
It's on stack. (check line 385).

juju/home.go
@@ -23,5 +26,20 @@ func InitJujuXDGDataHome() error {
if err := ssh.LoadClientKeys(osenv.JujuXDGDataHomePath("ssh")); err != nil {
return errors.Annotate(err, "cannot load ssh client keys")
}
+
+ base := osenv.JujuXDGDataHomePath("x509")
@axw

axw Jan 23, 2017

Member

are these bits needed any more? certs are loaded in the add-machine command (which is preferable, since it doesn't affect every command) -- does it need to be here too?

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

you are right I should drop this.

Contributor

hoenirvili commented Jan 23, 2017

!!build!!

Once the issues I've highlighted have been addressed, I will take one final pass. Nothing major jumps out at me.

+ }()
+
+ if err = InitAdministratorUser(&args); err != nil {
+ return machineId, errors.Annotatef(err,
@natefinch

natefinch Jan 5, 2017

Contributor

probably clearer to return "" rather than machineId, just so it's clear you're returning an empty string here

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

Have you pushed your fixes? I'm pretty sure Nate meant to use a string literal of "" here (i.e. return "", ...).

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ })
+
+ if err != nil {
+ logger.Errorf("Cannot obtain provisioning script")
@natefinch

natefinch Jan 5, 2017

Contributor

this error will handled at a higher level, so the log message here is probably redundant

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

+)
+
+type provisionerSuite struct {
+ testing.JujuConnSuite
@natefinch

natefinch Jan 5, 2017

Contributor

We're trying to avoid using JujuConnSuite for new tests. It's too slow, and requires too much hackery to make work.

I think we can test the majority of the code via unit tests, mocking out specific pieces, and then write a full CI test to do real provisioning with a real windows machine to test the end to end bits.

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+
+ scripts[0], err = shell.NewPSEncodedCommand(setFiles)
+ if err != nil {
+ return scripts, err
@natefinch

natefinch Jan 5, 2017

Contributor

in cases where there's an error, it's more appropriate to return nil, err, so we're not returning potentially partially formed data in the array of scripts.

In addition, you should use errors.Trace(err) so we keep stack info on the error.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+
+ provisioned, err := checkProvisioned(hostname, cli)
+ if err != nil {
+ err = fmt.Errorf("error checking is provisioned: %v", err)
@natefinch

natefinch Jan 5, 2017

Contributor

please use errors.Annotate here and below

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ // if it isn't one that the environment provider knows about.
+
+ instanceId := instance.Id(manual.ManualInstancePrefix + hostname)
+ nonce := fmt.Sprintf("%s:%s", instanceId, uuid.String())
@natefinch

natefinch Jan 5, 2017

Contributor

just FYI, you don't need the .String() on uuid. fmt.Sprintf will look for a .String() method if you're passing something into a %s format value.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+
+ provisioned := strings.Contains(stdout.String(), "Yes")
+ if stderr.Len() != 0 {
+ err = fmt.Errorf("%v (%v)", err, strings.TrimSpace(stderr.String()))
@natefinch

natefinch Jan 5, 2017

Contributor

please use errors.Annotatef here

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

+
+ udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg)
+ if err != nil {
+ return "", errors.Annotate(err, "error generating cloud-config")
@natefinch

natefinch Jan 5, 2017

Contributor

ideally you'd make these error messages distinct so it's more obvious which one is causing the problem.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@axw

axw Jan 24, 2017

Member

Please make these errors distinct from one other.

+
+ hc, ser, err := winrmprovisioner.DetectSeriesAndHardwareCharacteristics(winrmListenerAddr, fakeCli)
+ c.Assert(err, gc.IsNil)
+ c.Assert((len(ser) > 0), gc.Equals, true)
@natefinch

natefinch Jan 5, 2017

Contributor

this is extraneous, with the check on line 71

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

You can drop this line as Nate mentions, but FYI for future: you can use c.Assert(ser, gc.Not(gc.HasLen), 0). This preserves the value of ser for the error message.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ c.Assert((len(ser) > 0), gc.Equals, true)
+ c.Assert(hc, gc.NotNil)
+ c.Assert(ser, jc.DeepEquals, series)
+ c.Assert(*hc.Arch, jc.DeepEquals, arch)
@natefinch

natefinch Jan 5, 2017

Contributor

you can just use gc.Equals for strings

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@hoenirvili

hoenirvili Jan 23, 2017

Contributor

Fixed !

+ var stdin, stderr bytes.Buffer
+ fakeCli := &fakeWinRM{
+ fakeRun: func(cmd string, stdout, stderr io.Writer) error {
+ c.Assert((len(cmd) > 0), gc.Equals, true)
@natefinch

natefinch Jan 5, 2017

Contributor

seems like we could do a smarter assert than this

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

Revert back to make use of the cert authentication client.
Signed-off-by: Giulitti Salvatore <sgiulitti@cloudbasesolutions.com>
Contributor

hoenirvili commented Jan 23, 2017

!!build!!

axw approved these changes Jan 24, 2017

A few little things, otherwise LGTM. Please run tests with -race before merging.

+ t.Skip("Manual provider as client is not supported on windows")
+ }
+
+ testing.MgoTestPackage(t)
@axw

axw Jan 24, 2017

Member

Now that you're not using JujuConnSuite, MgoTestPackage isn't needed. Please use gocheck.TestingT(t) instead

@hoenirvili

hoenirvili Jan 24, 2017

Contributor

Fixed !

+
+ provisioned := strings.Contains(stdout.String(), "Yes")
+ if stderr.Len() != 0 {
+ err = errors.Annotatef(err, "%v (%v)", err, strings.TrimSpace(stderr.String()))
@axw

axw Jan 24, 2017

Member

Annotatef already includes the original error in the message. Please change this to:

err = errors.Annotate(err, strings.TrimSpace(stderr.String()))

@hoenirvili

hoenirvili Jan 24, 2017

Contributor

Fixed !

+
+ udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg)
+ if err != nil {
+ return "", errors.Annotate(err, "error generating cloud-config")
@natefinch

natefinch Jan 5, 2017

Contributor

ideally you'd make these error messages distinct so it's more obvious which one is causing the problem.

@hoenirvili

hoenirvili Jan 9, 2017

Contributor

Fixed !

@axw

axw Jan 23, 2017

Member

This has not been addressed.

@axw

axw Jan 24, 2017

Member

Please make these errors distinct from one other.

Changes after review.
Signed-off-by: Giulitti Salvatore <sgiulitti@cloudbasesolutions.com>
Contributor

hoenirvili commented Jan 24, 2017

$$merge$$

Contributor

jujubot commented Jan 24, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

Contributor

jujubot commented Jan 24, 2017

Build failed: Tests failed
build url: http://juju-ci.vapour.ws:8080/job/github-merge-juju/10094

Contributor

hoenirvili commented Jan 24, 2017

$$merge$$

Contributor

jujubot commented Jan 24, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

Contributor

jujubot commented Jan 24, 2017

Build failed: Tests failed
build url: http://juju-ci.vapour.ws:8080/job/github-merge-juju/10097

Contributor

hoenirvili commented Jan 24, 2017

$$merge$$

Contributor

jujubot commented Jan 24, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

@jujubot jujubot merged commit 3dcb717 into juju:develop Jan 24, 2017

1 check failed

github-check-merge-juju Built PR, ran unit tests, and tested LXD deploy. Use !!.*!! to request another build. IE, !!build!!, !!retry!!
Details

@hoenirvili hoenirvili deleted the hoenirvili:enable-windows-provisioner branch Jan 24, 2017

Member

axw commented Jan 24, 2017

This is a big deal. Thank you for your perseverance and congrats on getting it landed @hoenirvili :)

Contributor

hoenirvili commented Jan 25, 2017

@axw Thanks man, you welcome. I actually enjoyed writing and contribute my code to this wonderful community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment