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

etcdctl: allow move-leader to connect to multiple endpoints with TLS #12757

Closed
wants to merge 1 commit into from

Conversation

zerodayz
Copy link

@zerodayz zerodayz commented Mar 9, 2021

Re-opening closed PR #11775 which was originaly authored by benmoss.

The mustClientForCmd function is responsible for parsing environment
variables and flags into configuration data. A change was made in #9382
to call Fatal if a flag is provided multiple times. This means that we
cannot call the mustClientForCmd function more than once,
since it will think that flags parsed the first time are now
being redefined and error out.

Some people have commented about this in #8380 but I don't think
there's an open issue for it.

Please read https://github.com/etcd-io/etcd/blob/master/CONTRIBUTING.md#contribution-flow.

@zerodayz
Copy link
Author

zerodayz commented Mar 9, 2021

From @ptabor in #11775 working on the test

Could you, please, add a regression test.
Probably this file is a convenient place and a template:

./tests/e2e/ctl_v3_move_leader_test.go

@zerodayz
Copy link
Author

@ptabor I continued from where Ben Moss finished #11775 . Please can you review?

I noticed that etcd would fail to move-leader using the env variables set. If using CmdArgs it works.

This patch fixed that and also added a test which would fail without this patch, what it does it's setting up the Env Variables and executes move-leader.

I can't loop thru many tests there, as the tc.prefixes are pre-configuring the variables, meaning the last test values would always overwrite the previous one.

I couldn't figure out if I can pass the cx.envMap as part of the test, however this test showed the fix actually works and should prevent from regression in the future.

Thanks!

tests/e2e/ctl_v3_move_leader_test.go Outdated Show resolved Hide resolved
tests/e2e/ctl_v3_move_leader_test.go Outdated Show resolved Hide resolved
tests/e2e/ctl_v3_move_leader_test.go Show resolved Hide resolved
envMap: map[string]struct{}{},
}

tests := []struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we need to have different testcases for different tests... let's expose tests as this method parameter.

Copy link
Author

Choose a reason for hiding this comment

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

I think we should have exact same test cases. I am executing:

func TestCtlV3MoveLeaderSecure(t *testing.T) {
	testCtlV3MoveLeader(t, withCfg(*newConfigTLS()))
	testCtlV3MoveLeader(t, withCfg(*newConfigTLS()), withFlagByEnv())
}

func TestCtlV3MoveLeaderInsecure(t *testing.T) {
	testCtlV3MoveLeader(t, withCfg(*newConfigNoTLS()))
	testCtlV3MoveLeader(t, withCfg(*newConfigNoTLS()), withFlagByEnv())
}

Move leader with and without env, which is correct way we need to test both. At the moment I am only fighting with:

	{
		{ // request to non-leader
			ret.prefixArgs([]string{ret.epc.EndpointsV3()[(leadIdx+1)%3]}),
			"no leader endpoint given at ",
		},
		{ // request to leader
			ret.prefixArgs([]string{ret.epc.EndpointsV3()[leadIdx]}),
			fmt.Sprintf("Leadership transferred from %s to %s", types.ID(leaderID), types.ID(transferee)),
		},
	}

The first test sets the leader to e.g. 2010 and connects to 2005, for example, so it should fail with:

no leader endpoint given at ",

But the second sets it to point to leader, with the CmdArgs it works, but with Env, it just gets overwritten and the first test is executed with Envs from the second test. I am trying to find out how to prevent that overwrites.

Copy link
Author

Choose a reason for hiding this comment

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

Whenever tc.prefixArgs is called it sets an env.

During populating tests struct it overwrites the Env.

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
Author

Choose a reason for hiding this comment

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

I think the best would be to add env into each test struct, what do you think @ptabor ?

@ptabor
Copy link
Contributor

ptabor commented Mar 11, 2021

Oh... that's weird. The tests should not modify the testing environment of test-process at all:

os.Setenv(ek, v)

instead it should pass its own environment map straight to:

return expect.NewExpectWithEnv(ctlBinPath, args[1:], env)

side by side to args []string

Thank you for catching it.

@zerodayz
Copy link
Author

Oh... that's weird. The tests should not modify the testing environment of test-process at all:

os.Setenv(ek, v)

instead it should pass its own environment map straight to:

return expect.NewExpectWithEnv(ctlBinPath, args[1:], env)

side by side to args []string

Thank you for catching it.

The code you point to is right but note that prefixArgs is called in

cx.prefixArgs([]string{cx.epc.EndpointsV3()[(leadIdx+1)%3]}),

and

cx.prefixArgs([]string{cx.epc.EndpointsV3()[leadIdx]}),

the second one overwrites the env in

os.Setenv(ek, v)

And then it goes thru the loop and spawn the process for first test in

if err := spawnWithExpect(cmdArgs, tc.expect); err != nil {

but it already has overwritten env variables.

@zerodayz
Copy link
Author

I have done some modifications, it still doesn't work due to issue with env, but let me push it so you can take a look.

@zerodayz
Copy link
Author

zerodayz commented Apr 5, 2021

@ptabor Did you have any time to look at those failing tests with Env Variables? I think the way the tests are written simply doesn't make it possible to use SetEnv. It will always get overwritten.

@zhangguanzhang
Copy link
Contributor

any update?

@zhangguanzhang
Copy link
Contributor

@gyuho any uddate?

@lilic
Copy link
Contributor

lilic commented Jun 11, 2021

@zerodayz do you mind rebasing so we can retrigger the tests you mentioned failed, thank you!

@zerodayz
Copy link
Author

Hi yeah sure I will do it today and see if the tests are fixed.

@zerodayz zerodayz force-pushed the fix-move-leader branch 2 times, most recently from af2ed4e to 10873b1 Compare June 14, 2021 09:48
@zerodayz
Copy link
Author

zerodayz commented Jun 14, 2021

Hi @lilic I rebased on main etcd-io. Also tried the Tests again with:

	testCtlV3MoveLeader(t, withCfg(*newConfigNoTLS()), withFlagByEnv())

And

		envMap:      map[string]struct{}{},

It's just that the tests simply overwrite each other when execute during initialization...

	tests := []struct {
		prefixes []string
		expect   string

	}{
		{ // request to non-leader
			cx.prefixArgs([]string{cx.epc.EndpointsV3()[(leadIdx+1)%3]}),
			"no leader endpoint given at ",
		},
		{ // request to leader
			cx.prefixArgs([]string{cx.epc.EndpointsV3()[leadIdx]}),
			fmt.Sprintf("Leadership transferred from %s to %s", types.ID(leaderID), types.ID(transferee)),
		},
	}

Feels like it does the prefixArgs first on both tests to populate the OS Env Variables. Then executes the first test, and then second.

So the first test is executed with Env variables from the second test..

expected: no leader endpoint given at
got: Leadership transferred from c61f33e98087dec2 to d70245c72180528a

Do you see what I mean ? ^

@lilic
Copy link
Contributor

lilic commented Jun 14, 2021

Did the test fail, as you force pushed I could not see the previous failures, do you mind including them next time here, thanks!

@zerodayz
Copy link
Author

Including tests.

Re-opening closed PR etcd-io#11775 which was originaly authored by benmoss.

The mustClientForCmd function is responsible for parsing environment
variables and flags into configuration data. A change was made in etcd-io#9382
to call Fatal if a flag is provided multiple times. This means that we
cannot call the mustClientForCmd function more than once,
since it will think that flags parsed the first time are now
being redefined and error out.

Some people have commented about this in etcd-io#8380 but I don't think
there's an open issue for it.
@zerodayz
Copy link
Author

@lilic Included updated tests, please try to debug in your Env. And you will see what I mean.

@zerodayz
Copy link
Author

This is only failing of course if the tests with Env contains two tests, if I add test one by one separately, this works. So I just think the way how the tests are written, the OS Env variables are being overwritten before the tests are actually executed. So last lest variables are used for the first test.

Copy link
Contributor

@lilic lilic left a comment

Choose a reason for hiding this comment

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

I left a suggestion, there is also an issue with gofmt see the failing test for that.

@@ -28,25 +28,34 @@ import (
)

func TestCtlV3MoveLeaderSecure(t *testing.T) {
testCtlV3MoveLeader(t, *newConfigTLS())
testCtlV3MoveLeader(t, withCfg(*newConfigTLS()))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you explain why calling this twice is needed change? I would suggest keeping the existing tests as is and add a new test case that tests the different scenarios you have, e.g. endpoints connection. This way failures would be more evident. Unless I am missing something here?

@lilic
Copy link
Contributor

lilic commented Jun 14, 2021

This is only failing of course if the tests with Env contains two tests, if I add test one by one separately, this works. So I just think the way how the tests are written, the OS Env variables are being overwritten before the tests are actually executed. So last lest variables are used for the first test.

By two tests you mean where you call testCtlV3MoveLeader twice? I left a suggestion asking why this is needed even for the existing tests?

@zhangguanzhang
Copy link
Contributor

any update?

3 similar comments
@zhangguanzhang
Copy link
Contributor

any update?

@lqhandsome
Copy link

any update?

@hong108
Copy link

hong108 commented Jun 24, 2021

any update?

@zhangguanzhang
Copy link
Contributor

any update? 2021/07-08

@lilic
Copy link
Contributor

lilic commented Jul 13, 2021

@zerodayz hey 👋 would you prefer someone else to take over the PR with your commits maybe to finish this up?

@zhangguanzhang
Copy link
Contributor

any update? 2021/08-05

@lilic
Copy link
Contributor

lilic commented Aug 5, 2021

Since its been some time, i would suggest someone else take this over with @zerodayz commits of course. @zhangguanzhang since you are interested in this, do you want to take the commits and open a new PR and fix the tests?

@stale
Copy link

stale bot commented Nov 4, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 21 days if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 4, 2021
@stale stale bot closed this Nov 25, 2021
tjungblu added a commit to tjungblu/etcd that referenced this pull request Aug 3, 2022
Re-opening closed PR etcd-io#11775 which was originaly authored by benmoss.
Then again opened PR etcd-io#12757 which was authored by zerodayz.

The mustClientForCmd function is responsible for parsing environment
variables and flags into configuration data. A change was made in etcd-io#9382
to call Fatal if a flag is provided multiple times. This means that we
cannot call the mustClientForCmd function more than once,
since it will think that flags parsed the first time are now
being redefined and error out.

Some people have commented about this in etcd-io#8380 but I don't think
there's an open issue for it.

Signed-off-by: Thomas Jungblut <tjungblu@redhat.com>
tjungblu added a commit to tjungblu/etcd that referenced this pull request Sep 7, 2022
Re-opening closed PR etcd-io#11775 which was originaly authored by benmoss.
Then again opened PR etcd-io#12757 which was authored by zerodayz.

The mustClientForCmd function is responsible for parsing environment
variables and flags into configuration data. A change was made in etcd-io#9382
to call Fatal if a flag is provided multiple times. This means that we
cannot call the mustClientForCmd function more than once,
since it will think that flags parsed the first time are now
being redefined and error out.

Some people have commented about this in etcd-io#8380 but I don't think
there's an open issue for it.

Signed-off-by: Thomas Jungblut <tjungblu@redhat.com>
tjungblu added a commit to tjungblu/etcd that referenced this pull request Sep 7, 2022
…ndpoints

Re-opening closed PR etcd-io#11775 which was originaly authored by benmoss.
Then again opened PR etcd-io#12757 which was authored by zerodayz.

The mustClientForCmd function is responsible for parsing environment
variables and flags into configuration data. A change was made in etcd-io#9382
to call Fatal if a flag is provided multiple times. This means that we
cannot call the mustClientForCmd function more than once,
since it will think that flags parsed the first time are now
being redefined and error out.

Some people have commented about this in etcd-io#8380 but I don't think
there's an open issue for it.

Signed-off-by: Thomas Jungblut <tjungblu@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

6 participants