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

Added support for providing replicas #66

Merged
merged 1 commit into from
Apr 6, 2017

Conversation

surajssd
Copy link
Contributor

@surajssd surajssd commented Mar 10, 2017

A user can now provide the number of replicas of the
service that are needed, using a field called replicas
in opencompose service section.

This is an optional field, if nothing is provided then
the value defaults to 1.

Fixes #19

@kadel
Copy link
Member

kadel commented Mar 10, 2017

Commented in the original issue #19 (comment)

@tnozicka tnozicka self-requested a review March 10, 2017 19:10
Copy link
Contributor

@tnozicka tnozicka left a comment

Choose a reason for hiding this comment

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

@tnozicka
Copy link
Contributor

@surajssd FYI and to save you time, you need to move from int32 to *int32.

@@ -75,7 +75,7 @@ func GetValidatedObject(v *viper.Viper, cmd *cobra.Command, out, outerr io.Write

o, err := decoder.Decode(data)
if err != nil {
return nil, fmt.Errorf("could not unmarsha data for file '%s': %s", file, err)
return nil, fmt.Errorf("could not unmarshal data for file '%s': %s", file, err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please make it a different commit as it has no relation to Added support for providing replicas?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

// Set replica value only if it is given
if o.Replicas > 0 {
replicas := o.Replicas
d.Spec.Replicas = &replicas
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a better thing to do or should I do: d.Spec.Replicas = &o.Replicas ?
Thoughts: @tnozicka @containscafeine ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@surajssd d.Spec.Replicas = &o.Replicas should be fine, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@containscafeine i thought it will have to save entire object o to just assign value, until d is alive. But if I can copy it in some variable then it will be less wastage of resources?

Copy link
Contributor

@tnozicka tnozicka Mar 13, 2017

Choose a reason for hiding this comment

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

@surajssd d.Spec.Replicas = o.Replicas you should make o.Replicas pointer as well because it will be a pointer from the parser too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh yes, makes sense

@@ -319,6 +320,9 @@ func (d *Decoder) Decode(data []byte) (*object.OpenCompose, error) {
Name: string(s.Name),
}

// user given value of replicas
os.Replicas = s.Replicas
Copy link
Contributor Author

Choose a reason for hiding this comment

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

using values as it is here and checking down whether it should land in deployment or not? thoughts: @tnozicka

Copy link
Contributor

Choose a reason for hiding this comment

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

probably out-of date now

Image: "tomaskral/nonroot-nginx",
},
},
Replicas: 0,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

since using values as it is so not much changes, checks done at a level up when creating deployment, so original info is not lost from opencompose as well as in cluster.

@@ -184,6 +184,7 @@ func (c *Container) UnmarshalYAML(unmarshal func(interface{}) error) error {
type Service struct {
Name ResourceName `yaml:"name"`
Containers []Container `yaml:"containers"`
Replicas int32 `yaml:"replicas,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

it has to be a pointer here otherwise you can't distinguish between user setting 0 and not specifying the value

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

@@ -319,6 +320,9 @@ func (d *Decoder) Decode(data []byte) (*object.OpenCompose, error) {
Name: string(s.Name),
}

// user given value of replicas
os.Replicas = s.Replicas
Copy link
Contributor

Choose a reason for hiding this comment

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

probably out-of date now

@@ -106,6 +106,11 @@ func (t *Transformer) CreateDeployments(o *object.Service) ([]runtime.Object, er
},
}

// Set replica value only if it is given
if o.Replicas != nil {
d.Spec.Replicas = o.Replicas
Copy link
Contributor

Choose a reason for hiding this comment

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

only L111 is needed since it's now a pointer

@@ -419,5 +419,44 @@ volumes: []
continue
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like these unit test. We do table driven testing (a bit of Golang way) everywhere else.

There should be 2 unit tests for:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

@@ -319,6 +320,9 @@ func (d *Decoder) Decode(data []byte) (*object.OpenCompose, error) {
Name: string(s.Name),
}

// user given value of replicas
Copy link
Contributor

Choose a reason for hiding this comment

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

it's now a pointer to the value; maybe just drop the comment since its obvious anyway

@surajssd surajssd force-pushed the replicas branch 2 times, most recently from 546162d to df245ff Compare March 15, 2017 15:29
version: 0.1-dev
services:
- name: helloworld
replicas: -1
Copy link
Contributor Author

Choose a reason for hiding this comment

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

even after giving value as negative this test passes, since the check on negativity happens later? Apart from adding tests about createdeployment and verifying this actually fails @tnozicka do you have any thought on handling this well?

Copy link
Contributor

Choose a reason for hiding this comment

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

parser should check this

} else {
return nil, fmt.Errorf("Replica count is negative in service: %q", o.Name)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is where I have added the check and this is needed otherwise the artifact is generated with negative number and k8s won't take that!

Copy link
Contributor

Choose a reason for hiding this comment

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

actually, parser should be the one checking that since it's invalid input

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added checks to parser as well

Copy link
Member

Choose a reason for hiding this comment

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

If this is checked in parser, does it make sense to check it here again?

Copy link
Contributor

Choose a reason for hiding this comment

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

@kadel agreed. That's what my previous comment was suppose to mean (move, not copy the check) - this isn't task transformer should do

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I remove check from here, how do we address the condition where someone wants to use the opencompose as lib?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and we wanna do the validation? ideally for an app like this where data is coming from multiple places we should have a layer which does it for us? WDYT @tnozicka ?

Copy link
Member

@kadel kadel Mar 27, 2017

Choose a reason for hiding this comment

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

May be we could use object.Validate for this.

All validation logic should be in one place

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this makes sense to me!

} else {
return nil, fmt.Errorf("Replica count is negative in service: %q", o.Name)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

actually, parser should be the one checking that since it's invalid input

}

for _, test := range tests {
t.Logf("Running test: %q", test.Name)
Copy link
Contributor

Choose a reason for hiding this comment

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

version: 0.1-dev
services:
- name: helloworld
replicas: -1
Copy link
Contributor

Choose a reason for hiding this comment

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

parser should check this

"Giving replica as string to see parsing fails",
false, `
name: frontend
replicas: notint
Copy link
Contributor

Choose a reason for hiding this comment

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

probably a typo: s/notint/nonint/ or s/notint/non-int/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just for showing this is 'not an integer' value

@surajssd surajssd force-pushed the replicas branch 5 times, most recently from ba67038 to 4b49e16 Compare March 16, 2017 10:03
@kadel
Copy link
Member

kadel commented Mar 20, 2017

Can you please update docs (file-reference) as part of this PR?

@surajssd
Copy link
Contributor Author

@kadel done!

| int32 | no |

Number of desired pods of this particluar service. This is an optional field.
If nothing is provided the artifact generated won't have anything either.
Copy link
Member

@kadel kadel Mar 22, 2017

Choose a reason for hiding this comment

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

I don't know about this sentence :-(
It won't say anything useful for people that are not familiar with Kubernetes.
I think that we should avoid mentioning generated artifacts as much as possible.

Copy link
Member

Choose a reason for hiding this comment

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

Can we just delete that last sentence sentence?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

@@ -38,11 +39,12 @@ Version of OpenCompose format.
Describes one service. Service can be composed of one or multiple containers which are scheduled
together and can communicate using localhost. (Containers in the same service share network namespace.)

Each service has name and list of the containers.
Each service has name, replicas and list of the containers.
Copy link
Contributor

Choose a reason for hiding this comment

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

it doesn't have to have replicas

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

@surajssd surajssd force-pushed the replicas branch 2 times, most recently from d702237 to b5b5086 Compare March 30, 2017 09:15
@surajssd
Copy link
Contributor Author

@kadel @tnozicka updated as you guys mentioned, will squash when you guys give LGTM!

// validate containers

// validate replicas
if err := validateReplicas(s.Replicas); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Stupid question as usual 😄
If replica check is just one line, and it is used in one place, does it make sense to have a separate function for it? Wouldn't be code more readable if actual check was here? 😇

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to make it testable so separated it out!

Copy link
Member

@kadel kadel Mar 30, 2017

Choose a reason for hiding this comment

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

than you testing separately one if statement?
I don't know, but for me it looks like it is just overcomplicating things

Validate can be tested as whole.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even I thought this might be overdoing but then there arent other tests so just for testing replicas I will need to create entire stucts object.

And here I can do specific tests like these one: https://github.com/redhat-developer/opencompose/pull/66/files#diff-4f9edbaf8553598b5a269f232bab233cR16

Copy link
Member

Choose a reason for hiding this comment

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

As soon as you add another validation test to this you will have to test whole Validate function anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated as per comments!

true,
&object.Service{
Name: name,
Replicas: goutil.Int32Addr(-1),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kadel also comment on this test?

`,
&Service{
Name: "frontend",
Replicas: goutil.Int32Addr(-1),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kadel also this test, please comment if this is needed ?

Copy link
Member

@kadel kadel left a comment

Choose a reason for hiding this comment

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

lgtm

@surajssd
Copy link
Contributor Author

surajssd commented Apr 1, 2017

@kadel is it okay to merge?

@kadel
Copy link
Member

kadel commented Apr 3, 2017

@kadel is it okay to merge?

lets wait for @tnozicka review

@surajssd
Copy link
Contributor Author

surajssd commented Apr 4, 2017

ping @tnozicka

#### replicas
| type | required |
|-------|----------|
| int32 | no |
Copy link
Contributor

Choose a reason for hiding this comment

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

wouldn't uint32 be more descriptive since any negative value is invalid. Or it would be good to mention it somewhere else

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should the internal object be also changed to uint32?

Copy link
Member

Choose a reason for hiding this comment

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

I think int32 in the code is ok.

I'm just thinking if it makes sense in documentation mention int32 type, maybe just integer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

}

for _, test := range tests {
t.Run(fmt.Sprintf("Running test: %q", test.Name), func(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There should be just a test name; go test tool will make the appropriate announcement on what is running

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


tests := []struct {
Name string
ExpectedSucess bool
Copy link
Contributor

Choose a reason for hiding this comment

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

consistent naming with the rest would be Succeed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

}

if !test.ExpectedSucess {
t.Errorf("Expected %#v to fail, but succeeded!", test.RawService)
Copy link
Contributor

Choose a reason for hiding this comment

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

you can merge these 2 lines by using t.Fatalf

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


for _, test := range tests {
if test.input != *test.output {
t.Errorf("The input and output doesn't match, for %d", test.input)
Copy link
Contributor

Choose a reason for hiding this comment

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

logically you should print both of those values to know what's wrong, not just input

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

// validate containers

// validate replicas
if s.Replicas != nil && *s.Replicas < 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

such checks should be done in the parser as I have mentioned in my previous comments. it's n invalid input for the parser and it is the only place we can have more info like a line number - and all the other checks are done in parser as well!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Logically, the value is valid for parser because parser is only supposed to parse data for its type and not validate if it is correct or not. That's the job of validator.

And I would like to have validation happening in only one place not twice. Someone using opencompose as lib might not be passing validated data so how are we gonna validate that?

Copy link
Member

Choose a reason for hiding this comment

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

Letes move on, and go with this as it is.
We can figure out how we are going to do all validations in another PR.

#92

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So we can merge this one?

Copy link
Member

Choose a reason for hiding this comment

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

see my other comment regarding docs (https://github.com/redhat-developer/opencompose/pull/66/files#r110106733)
than if you squash it, i think we can merge it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure on it now!


// validate replicas
if s.Replicas != nil && *s.Replicas < 0 {
return fmt.Errorf("Replica count is negative in service: %q", s.Name)
Copy link
Contributor

Choose a reason for hiding this comment

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

s/is/shall not be/


tests := []struct {
Name string
ExpectSuccess bool
Copy link
Contributor

Choose a reason for hiding this comment

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

non-consistent naming as above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!


transformer := Transformer{}
for _, test := range tests {

Copy link
Contributor

Choose a reason for hiding this comment

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

s/\n//

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

transformer := Transformer{}
for _, test := range tests {

t.Run(fmt.Sprintf("Running test: %q", test.Name), func(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

there should be just name of the test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

A user can now provide the number of replicas of the
service that are needed, using a field called `replicas`
in opencompose `service` section.

This is an optional field, if nothing is provided then
the no default value is assumed.

Fixes redhat-developer#19
@kadel kadel dismissed tnozicka’s stale review April 6, 2017 14:16

all issues addressed, validation will be fixed in another pr #92

@kadel kadel merged commit 59729ba into redhat-developer:master Apr 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants