Skip to content

Commit 2f1a83c

Browse files
committed
Add flag --log-credentials-errors
Currently container-suseconnect will print errors to the console when it fails to obtain the SLE credentials. This is however causing UX issues in the SLE BCI containers, which work perfectly fine without a SLE subscription. Thus a new flag is introduced: `--log-credentials-errors`. When this flag is set or if the environment variable `CONTAINER_SUSECONNECT_LOG_CREDENTIALS_ERR` is set, then `container-suseconnect` will continue printing errors as it did, but the default is now that errors with obtaining the credentials will be silently swallowed so that users of SLE BCI don't get confused by this error message. This fixes #62
1 parent 0d954a6 commit 2f1a83c

File tree

8 files changed

+104
-30
lines changed

8 files changed

+104
-30
lines changed

cmd/container-suseconnect/main.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ import (
2828
"github.com/urfave/cli/v2"
2929
)
3030

31+
func actionWrapper(action func(*cli.Context) error) func(*cli.Context) error {
32+
return func(ctx *cli.Context) error {
33+
if err := action(ctx); err != nil {
34+
switch err.(type) {
35+
case *cs.SuseConnectError:
36+
if err.(*cs.SuseConnectError).ErrorCode == cs.GetCredentialsError {
37+
if ctx.Bool("log-credentials-errors") {
38+
return err
39+
}
40+
return nil
41+
}
42+
43+
}
44+
return err
45+
}
46+
return nil
47+
}
48+
}
49+
3150
func main() {
3251
// Set the basic CLI metadata
3352
app := cli.NewApp()
@@ -55,13 +74,13 @@ func main() {
5574
defaultUsageAdditionListProducts := ""
5675
switch filepath.Base(os.Args[0]) {
5776
case "container-suseconnect-zypp":
58-
app.Action = runZypperPlugin
77+
app.Action = actionWrapper(runZypperPlugin)
5978
defaultUsageAdditionZypp = " (default)"
6079
case "susecloud":
61-
app.Action = runZypperURLResolver
80+
app.Action = actionWrapper(runZypperURLResolver)
6281
defaultUsageAdditionZypp = " (default)"
6382
default:
64-
app.Action = runListProducts
83+
app.Action = actionWrapper(runListProducts)
6584
defaultUsageAdditionListProducts = " (default)"
6685
}
6786

@@ -72,20 +91,28 @@ func main() {
7291
Aliases: []string{"lp"},
7392
Usage: fmt.Sprintf("List available products%v",
7493
defaultUsageAdditionListProducts),
75-
Action: runListProducts,
94+
Action: actionWrapper(runListProducts),
7695
},
7796
{
7897
Name: "list-modules",
7998
Aliases: []string{"lm"},
8099
Usage: "List available modules",
81-
Action: runListModules,
100+
Action: actionWrapper(runListModules),
82101
},
83102
{
84103
Name: "zypper",
85104
Aliases: []string{"z", "zypp"},
86105
Usage: fmt.Sprintf("Run the zypper service plugin%v",
87106
defaultUsageAdditionZypp),
88-
Action: runZypperPlugin,
107+
Action: actionWrapper(runZypperPlugin),
108+
},
109+
}
110+
111+
app.Flags = []cli.Flag{
112+
&cli.BoolFlag{
113+
Name: "log-credentials-errors",
114+
Usage: "Print errors with your credentials",
115+
EnvVars: []string{"CONTAINER_SUSECONNECT_LOG_CREDENTIALS_ERR"},
89116
},
90117
}
91118

internal/configuration.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ func ReadConfiguration(config Configuration) error {
6868
if config.onLocationsNotFound() {
6969
return nil
7070
}
71-
return loggedError("Warning: SUSE credentials not found: %v - automatic handling of repositories not done.", config.locations())
71+
return loggedError(GetCredentialsError, "Warning: SUSE credentials not found: %v - automatic handling of repositories not done.", config.locations())
7272
}
7373

7474
file, err := os.Open(path)
7575
if err != nil {
76-
return loggedError("Can't open %s file: %v", path, err.Error())
76+
return loggedError(GetCredentialsError, "Can't open %s file: %v", path, err.Error())
7777
}
7878
defer file.Close()
7979

@@ -96,7 +96,7 @@ func parse(config Configuration, reader io.Reader) error {
9696
line := scanner.Text()
9797
parts := strings.SplitN(line, string(config.separator()), 2)
9898
if len(parts) != 2 {
99-
return loggedError("Can't parse line: %v", line)
99+
return loggedError(GetCredentialsError, "Can't parse line: %v", line)
100100
}
101101

102102
// And finally trim the key and the value and pass it to the config.
@@ -106,7 +106,7 @@ func parse(config Configuration, reader io.Reader) error {
106106

107107
// Final checks.
108108
if err := scanner.Err(); err != nil {
109-
return loggedError("Error when scanning configuration: %v", err)
109+
return loggedError(GetCredentialsError, "Error when scanning configuration: %v", err)
110110
}
111111
if err := config.afterParseCheck(); err != nil {
112112
return err

internal/credentials.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ func (cr *Credentials) setValues(key, value string) {
5454

5555
func (cr *Credentials) afterParseCheck() error {
5656
if cr.Username == "" {
57-
return loggedError("Can't find username")
57+
return loggedError(GetCredentialsError, "Can't find username")
5858
}
5959
if cr.Password == "" {
60-
return loggedError("Can't find password")
60+
return loggedError(GetCredentialsError, "Can't find password")
6161
}
6262
return nil
6363
}

internal/error.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2022 SUSE LLC. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package containersuseconnect
16+
17+
const (
18+
// GetCredentialsError indicates a failure to retrieve or parse
19+
// credentials
20+
GetCredentialsError = iota
21+
// NetworkError is a placeholder for generic network communication
22+
// errors
23+
NetworkError = iota
24+
// InstalledProductError signals issues with the installed products
25+
InstalledProductError = iota
26+
// SubscriptionServerError means that the subscription server did
27+
// something unexpected
28+
SubscriptionServerError = iota
29+
// SubscriptionError marks issues with the actual subscription
30+
SubscriptionError = iota
31+
// RepositoryError indicates that there is something wrong with the
32+
// repository that the subscription server gave us
33+
RepositoryError = iota
34+
)
35+
36+
// SuseConnectError is a custom error type allowing us to distinguish between
37+
// different error kinds via the `ErrorCode` field
38+
type SuseConnectError struct {
39+
ErrorCode int
40+
message string
41+
}
42+
43+
func (s *SuseConnectError) Error() string {
44+
return s.message
45+
}

internal/installed_product.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,21 @@ func parseInstalledProduct(reader io.Reader) (InstalledProduct, error) {
6262
err := xml.Unmarshal(xmlData, &p)
6363
if err != nil {
6464
return InstalledProduct{},
65-
loggedError("Can't parse base product file: %v", err.Error())
65+
loggedError(InstalledProductError, "Can't parse base product file: %v", err.Error())
6666
}
6767
return p, nil
6868
}
6969

7070
// Read the product file from the standard location
7171
func readInstalledProduct(provider ProductProvider) (InstalledProduct, error) {
7272
if _, err := os.Stat(provider.Location()); os.IsNotExist(err) {
73-
return InstalledProduct{}, loggedError("No base product detected")
73+
return InstalledProduct{}, loggedError(InstalledProductError, "No base product detected")
7474
}
7575

7676
xmlFile, err := os.Open(provider.Location())
7777
if err != nil {
7878
return InstalledProduct{},
79-
loggedError("Can't open base product file: %v", err.Error())
79+
loggedError(InstalledProductError, "Can't open base product file: %v", err.Error())
8080
}
8181
defer xmlFile.Close()
8282

internal/logger.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package containersuseconnect
1616

1717
import (
18-
"errors"
1918
"fmt"
2019
"log"
2120
"os"
@@ -51,8 +50,11 @@ func GetLoggerFile() *os.File {
5150

5251
// Log the given formatted string with its parameters, and return it
5352
// as a new error.
54-
func loggedError(format string, params ...interface{}) error {
55-
str := fmt.Sprintf(format, params...)
56-
log.Print(str)
57-
return errors.New(str)
53+
func loggedError(errorCode int, format string, params ...interface{}) *SuseConnectError {
54+
msg := fmt.Sprintf(format, params...)
55+
log.Print(msg)
56+
return &SuseConnectError{
57+
ErrorCode: errorCode,
58+
message: msg,
59+
}
5860
}

internal/products.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func fixRepoUrlsForRMT(p *Product) error {
5656
for i := range p.Repositories {
5757
repourl, err := url.Parse(p.Repositories[i].URL)
5858
if err != nil {
59-
loggedError("Unable to parse repository URL: %s - %v", p.Repositories[i].URL, err)
59+
loggedError(RepositoryError, "Unable to parse repository URL: %s - %v", p.Repositories[i].URL, err)
6060
return err
6161
}
6262
params := repourl.Query()
@@ -84,7 +84,7 @@ func parseProducts(reader io.Reader) ([]Product, error) {
8484
data, err := ioutil.ReadAll(reader)
8585
if err != nil {
8686
return products,
87-
loggedError("Can't read product information: %v", err.Error())
87+
loggedError(RepositoryError, "Can't read product information: %v", err.Error())
8888
}
8989

9090
// Depending on which API was used the JSON we get passed contains
@@ -107,7 +107,7 @@ func parseProducts(reader io.Reader) ([]Product, error) {
107107
}
108108
if err != nil {
109109
return products,
110-
loggedError("Can't read product information: %v - %s", err.Error(), data)
110+
loggedError(RepositoryError, "Can't read product information: %v - %s", err.Error(), data)
111111
}
112112
return products, nil
113113
}
@@ -130,7 +130,7 @@ func requestProductsFromRegCodeOrSystem(data SUSEConnectData, regCode string,
130130
req, err := http.NewRequest("GET", data.SccURL, nil)
131131
if err != nil {
132132
return products,
133-
loggedError("Could not connect with registration server: %v\n", err)
133+
loggedError(NetworkError, "Could not connect with registration server: %v\n", err)
134134
}
135135

136136
values := req.URL.Query()
@@ -162,7 +162,7 @@ func requestProductsFromRegCodeOrSystem(data SUSEConnectData, regCode string,
162162
}
163163
}
164164
return products,
165-
loggedError("Unexpected error while retrieving products with regCode %s: %s", regCode, resp.Status)
165+
loggedError(SubscriptionServerError, "Unexpected error while retrieving products with regCode %s: %s", regCode, resp.Status)
166166
}
167167

168168
return parseProducts(resp.Body)

internal/subscriptions.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func requestRegcodes(data SUSEConnectData, credentials Credentials) ([]string, e
4444
req, err := http.NewRequest("GET", data.SccURL, nil)
4545
if err != nil {
4646
return codes,
47-
loggedError("Could not connect with registration server: %v\n", err)
47+
loggedError(NetworkError, "Could not connect with registration server: %v\n", err)
4848
}
4949

5050
req.URL.Path = "/connect/systems/subscriptions"
@@ -67,7 +67,7 @@ func requestRegcodes(data SUSEConnectData, credentials Credentials) ([]string, e
6767

6868
if resp.StatusCode != 200 {
6969
return codes,
70-
loggedError("Unexpected error while retrieving regcode: %s", resp.Status)
70+
loggedError(SubscriptionServerError, "Unexpected error while retrieving regcode: %s", resp.Status)
7171
}
7272

7373
subscriptions, err := parseSubscriptions(resp.Body)
@@ -88,15 +88,15 @@ func parseSubscriptions(reader io.Reader) ([]Subscription, error) {
8888

8989
data, err := ioutil.ReadAll(reader)
9090
if err != nil {
91-
return subscriptions, loggedError("Can't read subscriptions information: %v", err.Error())
91+
return subscriptions, loggedError(SubscriptionError, "Can't read subscriptions information: %v", err.Error())
9292
}
9393

9494
err = json.Unmarshal(data, &subscriptions)
9595
if err != nil {
96-
return subscriptions, loggedError("Can't read subscription: %v", err.Error())
96+
return subscriptions, loggedError(SubscriptionError, "Can't read subscription: %v", err.Error())
9797
}
9898
if len(subscriptions) == 0 {
99-
return subscriptions, loggedError("Got 0 subscriptions")
99+
return subscriptions, loggedError(SubscriptionError, "Got 0 subscriptions")
100100
}
101101
return subscriptions, nil
102102
}

0 commit comments

Comments
 (0)