Skip to content

Commit

Permalink
use distroless.dev/static base image (#1648)
Browse files Browse the repository at this point in the history
* closes #1621

* run hermes commands as root

(cherry picked from commit e011a10)

# Conflicts:
#	Dockerfile
#	tests/e2e/e2e_test.go
#	tests/e2e/e2e_util_test.go
  • Loading branch information
kirbyquerby authored and mergify[bot] committed Aug 10, 2022
1 parent b118baa commit 33188d3
Show file tree
Hide file tree
Showing 6 changed files with 473 additions and 4 deletions.
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ARG IMG_TAG=latest

# Compile the gaiad binary
FROM golang:1.18-alpine AS gaiad-builder
WORKDIR /src/app/
COPY go.mod go.sum* ./
RUN go mod download
COPY . .
ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3
RUN apk add --no-cache $PACKAGES
RUN CGO_ENABLED=0 make install

# Add to a distroless container
FROM distroless.dev/static:$IMG_TAG
ARG IMG_TAG
COPY --from=gaiad-builder /go/bin/gaiad /usr/local/bin/
EXPOSE 26656 26657 1317 9090
USER 0

ENTRYPOINT ["gaiad", "start"]
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ endif
.PHONY: run-tests $(TEST_TARGETS)

docker-build-debug:
@docker build -t cosmos/gaiad-e2e --build-arg IMG_TAG=debug -f e2e.Dockerfile .
@docker build -t cosmos/gaiad-e2e -f e2e.Dockerfile .

# TODO: Push this to the Cosmos Dockerhub so we don't have to keep building it
# in CI.
Expand Down
2 changes: 1 addition & 1 deletion e2e.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ RUN apk add --no-cache $PACKAGES
RUN CGO_ENABLED=0 make install

# Add to a distroless container
FROM gcr.io/distroless/cc:$IMG_TAG
FROM distroless.dev/static:$IMG_TAG
ARG IMG_TAG
COPY --from=gaiad-builder /go/bin/gaiad /usr/local/bin/
EXPOSE 26656 26657 1317 9090
Expand Down
7 changes: 5 additions & 2 deletions tests/e2e/e2e_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -211,7 +212,7 @@ func (s *IntegrationTestSuite) initGenesis(c *chain) {
bz, err = tmjson.MarshalIndent(genDoc, "", " ")
s.Require().NoError(err)

// write the updated genesis file to each validator
// write the updated genesis file to each validator.
for _, val := range c.validators {
writeFile(filepath.Join(val.configDir(), "config", "genesis.json"), bz)
}
Expand Down Expand Up @@ -271,11 +272,13 @@ func (s *IntegrationTestSuite) runValidators(c *chain, portOffset int) {
Name: val.instanceName(),
NetworkID: s.dkrNet.Network.ID,
Mounts: []string{
fmt.Sprintf("%s/:/root/.gaia", val.configDir()),
fmt.Sprintf("%s/:/home/nonroot/.gaia", val.configDir()),
},
Repository: "cosmos/gaiad-e2e",
}

s.Require().NoError(exec.Command("chmod", "-R", "0777", val.configDir()).Run())

// expose the first validator for debugging and communication
if val.index == 0 {
runOpts.PortBindings = map[docker.Port][]docker.PortBinding{
Expand Down
313 changes: 313 additions & 0 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,316 @@ func (s *IntegrationTestSuite) TestIBCTokenTransfer() {
s.Require().NotEmpty(ibcStakeDenom)
})
}
<<<<<<< HEAD
=======

func (s *IntegrationTestSuite) TestBankTokenTransfer() {
s.Run("send_photon_between_accounts", func() {
var err error

senderAddress, err := s.chainA.validators[0].keyInfo.GetAddress()
s.Require().NoError(err)
sender := senderAddress.String()

recipientAddress, err := s.chainA.validators[1].keyInfo.GetAddress()
s.Require().NoError(err)
recipient := recipientAddress.String()

chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp"))

var (
beforeSenderPhotonBalance sdk.Coin
beforeRecipientPhotonBalance sdk.Coin
)

s.Require().Eventually(
func() bool {
beforeSenderPhotonBalance, err = getSpecificBalance(chainAAPIEndpoint, sender, "photon")
s.Require().NoError(err)

beforeRecipientPhotonBalance, err = getSpecificBalance(chainAAPIEndpoint, recipient, "photon")
s.Require().NoError(err)

return beforeSenderPhotonBalance.IsValid() && beforeRecipientPhotonBalance.IsValid()
},
10*time.Second,
5*time.Second,
)

s.sendMsgSend(s.chainA, 0, sender, recipient, tokenAmount.String(), fees.String())

s.Require().Eventually(
func() bool {
afterSenderPhotonBalance, err := getSpecificBalance(chainAAPIEndpoint, sender, "photon")
s.Require().NoError(err)

afterRecipientPhotonBalance, err := getSpecificBalance(chainAAPIEndpoint, recipient, "photon")
s.Require().NoError(err)

decremented := beforeSenderPhotonBalance.Sub(tokenAmount).Sub(fees).IsEqual(afterSenderPhotonBalance)
incremented := beforeRecipientPhotonBalance.Add(tokenAmount).IsEqual(afterRecipientPhotonBalance)

return decremented && incremented
},
time.Minute,
5*time.Second,
)
})
}

func (s *IntegrationTestSuite) TestSendTokensFromNewGovAccount() {
s.writeGovProposals((s.chainA))
chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp"))
senderAddress, err := s.chainA.validators[0].keyInfo.GetAddress()
s.Require().NoError(err)
sender := senderAddress.String()
proposalCounter++
s.T().Logf("Proposal number: %d", proposalCounter)

s.fundCommunityPool(chainAAPIEndpoint, sender)

s.T().Logf("Submitting Legacy Gov Proposal: Community Spend Funding Gov Module")
s.submitLegacyProposalFundGovAccount(chainAAPIEndpoint, sender, proposalCounter)
s.T().Logf("Depositing Legacy Gov Proposal: Community Spend Funding Gov Module")
s.depositGovProposal(chainAAPIEndpoint, sender, proposalCounter)
s.T().Logf("Voting Legacy Gov Proposal: Community Spend Funding Gov Module")
s.voteGovProposal(chainAAPIEndpoint, sender, proposalCounter, "yes", false)

initialGovBalance, err := getSpecificBalance(chainAAPIEndpoint, govModuleAddress, photonDenom)
s.Require().NoError(err)
proposalCounter++

s.T().Logf("Submitting Gov Proposal: Sending Tokens from Gov Module to Recipient")
s.submitNewGovProposal(chainAAPIEndpoint, sender, proposalCounter, "/home/nonroot/.gaia/config/proposal_2.json")
s.T().Logf("Depositing Gov Proposal: Sending Tokens from Gov Module to Recipient")
s.depositGovProposal(chainAAPIEndpoint, sender, proposalCounter)
s.T().Logf("Voting Gov Proposal: Sending Tokens from Gov Module to Recipient")
s.voteGovProposal(chainAAPIEndpoint, sender, proposalCounter, "yes", false)
s.Require().Eventually(
func() bool {
newGovBalance, err := getSpecificBalance(chainAAPIEndpoint, govModuleAddress, photonDenom)
s.Require().NoError(err)

recipientBalance, err := getSpecificBalance(chainAAPIEndpoint, govSendMsgRecipientAddress, photonDenom)
s.Require().NoError(err)
return newGovBalance.IsEqual(initialGovBalance.Sub(sendGovAmount)) && recipientBalance.Equal(initialGovBalance.Sub(newGovBalance))
},
15*time.Second,
5*time.Second,
)
}

func (s *IntegrationTestSuite) TestGovSoftwareUpgrade() {
chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp"))
senderAddress, err := s.chainA.validators[0].keyInfo.GetAddress()
s.Require().NoError(err)
sender := senderAddress.String()
height := s.getLatestBlockHeight(s.chainA, 0)
proposalHeight := height + govProposalBlockBuffer
proposalCounter++

s.T().Logf("Writing proposal %d on chain %s", proposalCounter, s.chainA.id)
s.writeGovUpgradeSoftwareProposal(s.chainA, proposalHeight)

s.T().Logf("Submitting Gov Proposal: Software Upgrade")
s.submitNewGovProposal(chainAAPIEndpoint, sender, proposalCounter, "/home/nonroot/.gaia/config/proposal_3.json")
s.T().Logf("Depositing Gov Proposal: Software Upgrade")
s.depositGovProposal(chainAAPIEndpoint, sender, proposalCounter)
s.T().Logf("Weighted Voting Gov Proposal: Software Upgrade")
s.voteGovProposal(chainAAPIEndpoint, sender, proposalCounter, "yes=0.8,no=0.1,abstain=0.05,no_with_veto=0.05", true)

s.verifyChainHaltedAtUpgradeHeight(s.chainA, 0, proposalHeight)
s.T().Logf("Successfully halted chain at height %d", proposalHeight)

s.TearDownSuite()

s.T().Logf("Restarting containers")
s.SetupSuite()

s.Require().Eventually(
func() bool {
h := s.getLatestBlockHeight(s.chainA, 0)
s.Require().NoError(err)

return (h > 0)
},
30*time.Second,
5*time.Second,
)

proposalCounter = 0
}

func (s *IntegrationTestSuite) TestGovCancelSoftwareUpgrade() {
s.T().Skip()

chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp"))
senderAddress, err := s.chainA.validators[0].keyInfo.GetAddress()
s.Require().NoError(err)
sender := senderAddress.String()
height := s.getLatestBlockHeight(s.chainA, 0)
proposalHeight := height + 50
proposalCounter++

s.T().Logf("Writing proposal %d on chain %s", proposalCounter, s.chainA.id)
s.writeGovUpgradeSoftwareProposal(s.chainA, proposalHeight)

s.T().Logf("Submitting Gov Proposal: Software Upgrade")
s.submitNewGovProposal(chainAAPIEndpoint, sender, proposalCounter, "/home/nonroot/.gaia/config/proposal_3.json")
s.depositGovProposal(chainAAPIEndpoint, sender, proposalCounter)
s.voteGovProposal(chainAAPIEndpoint, sender, proposalCounter, "yes", false)

proposalCounter++

s.T().Logf("Submitting Gov Proposal: Cancel Software Upgrade")
s.submitNewGovProposal(chainAAPIEndpoint, sender, proposalCounter, "/home/nonroot/.gaia/config/proposal_4.json")
s.depositGovProposal(chainAAPIEndpoint, sender, proposalCounter)
s.voteGovProposal(chainAAPIEndpoint, sender, proposalCounter, "yes", false)

s.verifyChainPassesUpgradeHeight(s.chainA, 0, proposalHeight)
s.T().Logf("Successfully canceled upgrade at height %d", proposalHeight)
}

func (s *IntegrationTestSuite) fundCommunityPool(chainAAPIEndpoint, sender string) {
s.Run("fund_community_pool", func() {
beforeDistPhotonBalance, _ := getSpecificBalance(chainAAPIEndpoint, distModuleAddress, tokenAmount.Denom)
if beforeDistPhotonBalance.IsNil() {
// Set balance to 0 if previous balance does not exist
beforeDistPhotonBalance = sdk.NewInt64Coin("photon", 0)
}

s.execDistributionFundCommunityPool(s.chainA, 0, chainAAPIEndpoint, sender, tokenAmount.String(), fees.String())

// there are still tokens being added to the community pool through block production rewards but they should be less than 500 tokens
marginOfErrorForBlockReward := sdk.NewInt64Coin("photon", 500)

s.Require().Eventually(
func() bool {
afterDistPhotonBalance, err := getSpecificBalance(chainAAPIEndpoint, distModuleAddress, tokenAmount.Denom)
if err != nil {
s.T().Logf("Error getting balance: %s", afterDistPhotonBalance)
}
s.Require().NoError(err)

return afterDistPhotonBalance.Sub(beforeDistPhotonBalance.Add(tokenAmount.Add(fees))).IsLT(marginOfErrorForBlockReward)
},
15*time.Second,
5*time.Second,
)
})
}

func (s *IntegrationTestSuite) submitLegacyProposalFundGovAccount(chainAAPIEndpoint, sender string, proposalId int) {
s.Run("submit_legacy_community_spend_proposal_to_fund_gov_acct", func() {
s.execGovSubmitLegacyGovProposal(s.chainA, 0, chainAAPIEndpoint, sender, "/home/nonroot/.gaia/config/proposal.json", fees.String(), "community-pool-spend")

s.Require().Eventually(
func() bool {
proposal, err := queryGovProposal(chainAAPIEndpoint, proposalId)
s.Require().NoError(err)

return (proposal.GetProposal().Status == govv1beta1.StatusDepositPeriod)
},
15*time.Second,
5*time.Second,
)
})
}

func (s *IntegrationTestSuite) submitNewGovProposal(chainAAPIEndpoint, sender string, proposalId int, proposalPath string) {
s.Run("submit_new_gov_proposal", func() {
s.execGovSubmitProposal(s.chainA, 0, chainAAPIEndpoint, sender, proposalPath, fees.String())

s.Require().Eventually(
func() bool {
proposal, err := queryGovProposal(chainAAPIEndpoint, proposalId)
s.T().Logf("Proposal: %s", proposal.String())
s.Require().NoError(err)

return (proposal.GetProposal().Status == govv1beta1.StatusDepositPeriod)
},
15*time.Second,
5*time.Second,
)
})
}

func (s *IntegrationTestSuite) depositGovProposal(chainAAPIEndpoint, sender string, proposalId int) {
s.Run("deposit_gov_proposal", func() {
s.execGovDepositProposal(s.chainA, 0, chainAAPIEndpoint, sender, proposalId, depositAmount.String(), fees.String())

s.Require().Eventually(
func() bool {
proposal, err := queryGovProposal(chainAAPIEndpoint, proposalId)
s.Require().NoError(err)

return (proposal.GetProposal().Status == govv1beta1.StatusVotingPeriod)
},
15*time.Second,
5*time.Second,
)
})
}

func (s *IntegrationTestSuite) voteGovProposal(chainAAPIEndpoint, sender string, proposalId int, vote string, weighted bool) {
s.Run("vote_gov_proposal", func() {
if weighted {
s.execGovWeightedVoteProposal(s.chainA, 0, chainAAPIEndpoint, sender, proposalId, vote, fees.String())
} else {
s.execGovVoteProposal(s.chainA, 0, chainAAPIEndpoint, sender, proposalId, vote, fees.String())
}

s.Require().Eventually(
func() bool {
proposal, err := queryGovProposal(chainAAPIEndpoint, proposalId)
s.Require().NoError(err)

return (proposal.GetProposal().Status == govv1beta1.StatusPassed)
},
15*time.Second,
5*time.Second,
)
})
}

func (s *IntegrationTestSuite) verifyChainHaltedAtUpgradeHeight(c *chain, valIdx, upgradeHeight int) {
s.Require().Eventually(
func() bool {
currentHeight := s.getLatestBlockHeight(c, valIdx)

return currentHeight == upgradeHeight
},
30*time.Second,
5*time.Second,
)

counter := 0
s.Require().Eventually(
func() bool {
currentHeight := s.getLatestBlockHeight(c, valIdx)

if currentHeight > upgradeHeight {
return false
}
if currentHeight == upgradeHeight {
counter++
}
return counter >= 2
},
8*time.Second,
2*time.Second,
)
}

func (s *IntegrationTestSuite) verifyChainPassesUpgradeHeight(c *chain, valIdx, upgradeHeight int) {
s.Require().Eventually(
func() bool {
currentHeight := s.getLatestBlockHeight(c, valIdx)

return currentHeight > upgradeHeight
},
30*time.Second,
5*time.Second,
)
}
>>>>>>> e011a10 (use distroless.dev/static base image (#1648))
Loading

0 comments on commit 33188d3

Please sign in to comment.