Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions api/types/installers/installer.sh.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,10 @@ on_azure() {
PACKAGE_LIST="${PACKAGE_LIST} {{ .TeleportPackage }}-updater"
fi

# old versions of ubuntu require that keys get added by `apt-key add`, without
# adding the key apt shows a key signing error when installing teleport.
LEGACY_UBUNTU=false
if [ "$VERSION_CODENAME" = "xenial" ] || [ "$VERSION_CODENAME" = "trusty" ]; then
LEGACY_UBUNTU=true
fi

if [ "$ID" = "debian" ] || [ "$ID" = "ubuntu" ]; then
if [ "$LEGACY_UBUNTU" = true ]; then
# old versions of ubuntu require that keys get added by `apt-key add`, without
# adding the key apt shows a key signing error when installing teleport.
if [ "$VERSION_CODENAME" = "xenial" ] || [ "$VERSION_CODENAME" = "trusty" ]; then
curl -o /tmp/teleport-pubkey.asc https://apt.releases.teleport.dev/gpg
sudo apt-key add /tmp/teleport-pubkey.asc
echo "deb https://apt.releases.teleport.dev/ubuntu ${VERSION_CODENAME?} {{ .RepoChannel }}" | sudo tee /etc/apt/sources.list.d/teleport.list
Expand Down
75 changes: 75 additions & 0 deletions lib/automaticupgrades/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2023 Gravitational, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package automaticupgrades

import (
"context"
"net/http"
"net/url"
"strings"

"github.com/gravitational/trace"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/utils"
)

const (
// stableCloudVersionBaseURL is the base URL for the server that returns the current stable/cloud version.
stableCloudVersionBaseURL = "https://updates.releases.teleport.dev"

// stableCloudVersionPath is the URL path that returns the current stable/cloud version.
stableCloudVersionPath = "/v1/stable/cloud/version"
)

// Version returns the version that should be used for installing Teleport Services
// This is used when installing agents using scripts.
// Even when Teleport Auth/Proxy is using vX, the agents must always respect this version.
func Version(ctx context.Context, baseURL string) (string, error) {
if baseURL == "" {
baseURL = stableCloudVersionBaseURL
}

fullURL, err := url.JoinPath(baseURL, stableCloudVersionPath)
if err != nil {
return "", trace.Wrap(err)
}

req, err := http.NewRequestWithContext(ctx, http.MethodGet, fullURL, nil)
if err != nil {
return "", trace.Wrap(err)
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", trace.Wrap(err)
}
defer resp.Body.Close()

body, err := utils.ReadAtMost(resp.Body, teleport.MaxHTTPResponseSize)
if err != nil {
return "", trace.Wrap(err)
}

if resp.StatusCode != http.StatusOK {
return "", trace.BadParameter("invalid status code %d, body: %s", resp.StatusCode, string(body))
}

versionString := strings.TrimSpace(string(body))

return versionString, trace.Wrap(err)
}
86 changes: 86 additions & 0 deletions lib/automaticupgrades/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
Copyright 2023 Gravitational, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package automaticupgrades

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/gravitational/trace"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestVersion(t *testing.T) {
ctx := context.Background()

isBadParameterErr := func(tt require.TestingT, err error, i ...interface{}) {
require.True(tt, trace.IsBadParameter(err), "expected bad parameter, got %v", err)
}

for _, tt := range []struct {
name string
mockStatusCode int
mockResponseString string
errCheck require.ErrorAssertionFunc
expectedVersion string
}{
{
name: "real response",
mockStatusCode: http.StatusOK,
mockResponseString: "v13.1.1\n",
errCheck: require.NoError,
expectedVersion: "v13.1.1",
},
{
name: "invalid status code (500)",
mockStatusCode: http.StatusInternalServerError,
errCheck: isBadParameterErr,
},
{
name: "invalid status code (403)",
mockStatusCode: http.StatusForbidden,
errCheck: isBadParameterErr,
},
{
name: "valid but has spaces",
mockStatusCode: http.StatusOK,
mockResponseString: " v13.1.1 \n \r\n",
errCheck: require.NoError,
expectedVersion: "v13.1.1",
},
} {
t.Run(tt.name, func(t *testing.T) {
httpTestServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, r.URL.Path, "/v1/stable/cloud/version")
w.WriteHeader(tt.mockStatusCode)
w.Write([]byte(tt.mockResponseString))
}))
defer httpTestServer.Close()

v, err := Version(ctx, httpTestServer.URL)
tt.errCheck(t, err)
if err != nil {
return
}

require.Equal(t, v, tt.expectedVersion)
})
}
}
6 changes: 0 additions & 6 deletions lib/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/constants"
apiutils "github.com/gravitational/teleport/api/utils"
"github.com/gravitational/teleport/lib/modules"
)

// WriteContextCloser provides close method with context
Expand Down Expand Up @@ -506,11 +505,6 @@ func ReadOrMakeHostUUID(dataDir string) (string, error) {
return id, nil
}

// PrintVersion prints human readable version
func PrintVersion() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This change seems irrelevant to the issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was causing an import cycle because:

github.com/gravitational/teleport/lib/modules imports github.com/gravitational/teleport/lib/automaticupgrades imports github.com/gravitational/teleport/lib/utils imports github.com/gravitational/teleport/lib/modules: import cycle not allowed .

It was only used in our binaries and it was a one liner, so I just replaced the function call

modules.GetModules().PrintVersion()
}

// StringSliceSubset returns true if b is a subset of a.
func StringSliceSubset(a []string, b []string) error {
aset := make(map[string]bool)
Expand Down
12 changes: 6 additions & 6 deletions lib/web/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1701,20 +1701,20 @@ func (h *Handler) installer(w http.ResponseWriter, r *http.Request, p httprouter
// By default, it uses the stable/v<majorVersion> channel.
repoChannel := fmt.Sprintf("stable/%s", version)

// For Teleport Cloud installations, use the `stable/cloud` channel.
if feats.Cloud {
// If the updater must be installed, then change the repo to stable/cloud
// It must also install the version specified in
// https://updates.releases.teleport.dev/v1/stable/cloud/version
installUpdater := automaticUpgrades(h.ClusterFeatures)
if installUpdater {
repoChannel = stableCloudChannelRepo
}

// TODO(marco): remove BuildType check when teleport-upgrade (oss) package is available in apt/yum repos.
automaticUpgrades := feats.AutomaticUpgrades && modules.GetModules().BuildType() == modules.BuildEnterprise

tmpl := installers.Template{
PublicProxyAddr: h.PublicProxyAddr(),
MajorVersion: version,
TeleportPackage: teleportPackage,
RepoChannel: repoChannel,
AutomaticUpgrades: strconv.FormatBool(automaticUpgrades),
AutomaticUpgrades: strconv.FormatBool(installUpdater),
}
err = instTmpl.Execute(w, tmpl)
return nil, trace.Wrap(err)
Expand Down
Loading