Working client and Realm controller
This commit is contained in:
parent
fc6f1632da
commit
f949a523be
6 changed files with 339 additions and 27 deletions
|
@ -20,33 +20,29 @@ type Keycloak struct {
|
|||
user, pass, realm string
|
||||
}
|
||||
|
||||
func (kc *Keycloak) CreateRealmIfNotExists(ctx context.Context, realm gocloak.RealmRepresentation) error {
|
||||
func (kc *Keycloak) CreateRealm(ctx context.Context, realm gocloak.RealmRepresentation) error {
|
||||
_, err := kc.client.CreateRealm(ctx, kc.getToken(), realm)
|
||||
if isConflict(err) {
|
||||
log.Printf("Realm '%s' already exists, not updated", *realm.Realm)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (kc *Keycloak) CreateProviderIfNotExists(ctx context.Context, realm string, provider gocloak.IdentityProviderRepresentation) error {
|
||||
func (kc *Keycloak) UpdateRealm(ctx context.Context, realm gocloak.RealmRepresentation) error {
|
||||
return kc.client.UpdateRealm(ctx, kc.getToken(), realm)
|
||||
}
|
||||
|
||||
func (kc *Keycloak) CreateProvider(ctx context.Context, realm string, provider gocloak.IdentityProviderRepresentation) error {
|
||||
_, err := kc.client.CreateIdentityProvider(ctx, kc.getToken(), realm, provider)
|
||||
if isConflict(err) {
|
||||
log.Printf("Provider '%s/%s' already exists, not updated", realm, *provider.Alias)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (kc *Keycloak) CreateClientIfNotExists(ctx context.Context, realm string, c gocloak.Client) error {
|
||||
func (kc *Keycloak) CreateClient(ctx context.Context, realm string, c gocloak.Client) error {
|
||||
_, err := kc.client.CreateClient(ctx, kc.getToken(), realm, c)
|
||||
if isConflict(err) {
|
||||
log.Printf("Client '%s/%s' already exists, not updated", realm, *c.ClientID)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (kc *Keycloak) UpdateClient(ctx context.Context, realm string, c gocloak.Client) error {
|
||||
return kc.client.UpdateClient(ctx, kc.getToken(), realm, c)
|
||||
}
|
||||
|
||||
func New(url, user, pass, realm string) (*Keycloak, error) {
|
||||
kc := &Keycloak{}
|
||||
kc.client = gocloak.NewClient(url)
|
||||
|
|
62
controllers/keycloakclient.go
Normal file
62
controllers/keycloakclient.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
keycloakv1alpha1 "git.zom.bi/images/keycloak-operator/api/v1alpha1"
|
||||
"github.com/Nerzal/gocloak/v7"
|
||||
)
|
||||
|
||||
// ConvertToClient takes a CRD representation and converts it into a datatype
|
||||
// that can be understood by GoCloak.
|
||||
func ConvertToClient(clientCrd keycloakv1alpha1.KeycloakClient) (gocloak.Client, error) {
|
||||
var client gocloak.Client
|
||||
|
||||
clientSpec := clientCrd.Spec
|
||||
|
||||
// Mandatory Properties
|
||||
client.ClientID = &clientSpec.ClientID
|
||||
|
||||
// Optional Properties
|
||||
client.Enabled = clientSpec.Enabled
|
||||
client.Name = clientSpec.Name
|
||||
client.Description = clientSpec.Description
|
||||
client.Protocol = clientSpec.Protocol
|
||||
client.ClientAuthenticatorType = clientSpec.ClientAuthenticatorType
|
||||
client.DirectAccessGrantsEnabled = clientSpec.DirectAccessGrantsEnabled
|
||||
client.PublicClient = clientSpec.PublicClient
|
||||
client.ImplicitFlowEnabled = clientSpec.ImplicitFlowEnabled
|
||||
client.StandardFlowEnabled = clientSpec.StandardFlowEnabled
|
||||
client.ServiceAccountsEnabled = clientSpec.ServiceAccountsEnabled
|
||||
client.RegistrationAccessToken = clientSpec.RegistrationAccessToken
|
||||
client.SurrogateAuthRequired = clientSpec.SurrogateAuthRequired
|
||||
client.BearerOnly = clientSpec.BearerOnly
|
||||
client.ConsentRequired = clientSpec.ConsentRequired
|
||||
client.DefaultClientScopes = clientSpec.DefaultClientScopes
|
||||
client.OptionalClientScopes = clientSpec.OptionalClientScopes
|
||||
client.BaseURL = clientSpec.BaseURL
|
||||
client.RootURL = clientSpec.RootURL
|
||||
client.AdminURL = clientSpec.AdminURL
|
||||
client.RedirectURIs = clientSpec.RedirectURIs
|
||||
client.WebOrigins = clientSpec.WebOrigins
|
||||
|
||||
if clientSpec.Secret != nil {
|
||||
// TODO
|
||||
// client.Secret = ""
|
||||
}
|
||||
|
||||
// client.Access = ""
|
||||
// client.Attributes = ""
|
||||
// client.AuthenticationFlowBindingOverrides = ""
|
||||
// client.AuthorizationServicesEnabled = ""
|
||||
// client.AuthorizationSettings = ""
|
||||
// client.DefaultRoles = ""
|
||||
// client.FrontChannelLogout = ""
|
||||
// client.FullScopeAllowed = ""
|
||||
// client.ID = ""
|
||||
// client.NodeReRegistrationTimeout = ""
|
||||
// client.NotBefore = ""
|
||||
// client.Origin = ""
|
||||
// client.ProtocolMappers = ""
|
||||
// client.RegisteredNodes = ""
|
||||
|
||||
return client, nil
|
||||
}
|
|
@ -19,7 +19,9 @@ package controllers
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Nerzal/gocloak/v7"
|
||||
"github.com/go-logr/logr"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
@ -50,9 +52,79 @@ type KeycloakClientReconciler struct {
|
|||
// For more details, check Reconcile and its Result here:
|
||||
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.7.0/pkg/reconcile
|
||||
func (r *KeycloakClientReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
_ = r.Log.WithValues("keycloakclient", req.NamespacedName)
|
||||
log := r.Log.WithValues("keycloakclient", req.NamespacedName)
|
||||
|
||||
// your logic here
|
||||
log.Info("reconciling")
|
||||
|
||||
// We get the information from the CRD
|
||||
var client keycloakv1alpha1.KeycloakClient
|
||||
if err := r.Get(ctx, req.NamespacedName, &client); err != nil {
|
||||
if apierrs.IsNotFound(err) {
|
||||
// Client is already deleted via finalizer.
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if !client.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
// is in the process of being deleted
|
||||
if containsString(client.ObjectMeta.Finalizers, FinalizerName) {
|
||||
// our finalizer is present, so lets handle any external dependency
|
||||
|
||||
// We do not want to delete anything, so we just disable the client.
|
||||
disabled := gocloak.Client{ClientID: &client.Spec.ClientID, Enabled: gocloak.BoolP(false)}
|
||||
err := r.Keycloak.UpdateClient(ctx, client.Spec.RealmName, disabled)
|
||||
if err != nil {
|
||||
// if fail to delete the external dependency here, return with error
|
||||
// so that it can be retried
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
// remove our finalizer from the list and update it.
|
||||
client.ObjectMeta.Finalizers = removeString(client.ObjectMeta.Finalizers, FinalizerName)
|
||||
if err := r.Update(ctx, &client); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
log.Info("Deleted the client")
|
||||
}
|
||||
|
||||
// done
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// Its not being deleted, so we seize the moment to take ownership.
|
||||
if !containsString(client.ObjectMeta.Finalizers, FinalizerName) {
|
||||
typeMeta := client.TypeMeta
|
||||
client.ObjectMeta.Finalizers = append(client.ObjectMeta.Finalizers, FinalizerName)
|
||||
if err := r.Update(ctx, &client); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
// restore the TypeMeta object as it is removed during Update, but need to be accessed later
|
||||
client.TypeMeta = typeMeta
|
||||
}
|
||||
|
||||
// Convert Client
|
||||
keycloakClient, err := ConvertToClient(client)
|
||||
if err != nil {
|
||||
log.Error(err, "Could not convert client")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
err = r.Keycloak.CreateClient(ctx, client.Spec.RealmName, keycloakClient)
|
||||
if err != nil {
|
||||
// try updating instead
|
||||
err := r.Keycloak.UpdateClient(ctx, client.Spec.RealmName, keycloakClient)
|
||||
if err != nil {
|
||||
log.Error(err, "Could not create/update client")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
log.Info("Updated the client")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
client.Status.Available = true
|
||||
r.Status().Update(ctx, &client)
|
||||
log.Info("Successfully created client")
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
|
131
controllers/keycloakrealm.go
Normal file
131
controllers/keycloakrealm.go
Normal file
|
@ -0,0 +1,131 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
keycloakv1alpha1 "git.zom.bi/images/keycloak-operator/api/v1alpha1"
|
||||
"github.com/Nerzal/gocloak/v7"
|
||||
)
|
||||
|
||||
// ConvertToRealm takes a CRD representation and converts it into a datatype
|
||||
// that can be understood by GoCloak.
|
||||
func ConvertToRealm(realmCrd keycloakv1alpha1.KeycloakRealm) (gocloak.RealmRepresentation, error) {
|
||||
var realm gocloak.RealmRepresentation
|
||||
|
||||
realmSpec := realmCrd.Spec
|
||||
|
||||
// Mandatory Properties
|
||||
realm.Realm = &realmSpec.RealmName
|
||||
|
||||
// Optional Properties
|
||||
realm.Enabled = realmSpec.Enabled
|
||||
realm.DisplayName = realmSpec.DisplayName
|
||||
realm.DisplayNameHTML = realmSpec.DisplayNameHTML
|
||||
realm.LoginTheme = realmSpec.LoginTheme
|
||||
realm.LoginWithEmailAllowed = realmSpec.LoginWithEmailAllowed
|
||||
realm.RegistrationAllowed = realmSpec.RegistrationAllowed
|
||||
realm.EditUsernameAllowed = realmSpec.EditUsernameAllowed
|
||||
realm.RegistrationEmailAsUsername = realmSpec.RegistrationEmailAsUsername
|
||||
realm.ResetPasswordAllowed = realmSpec.ResetPasswordAllowed
|
||||
realm.DuplicateEmailsAllowed = realmSpec.DuplicateEmailsAllowed
|
||||
realm.VerifyEmail = realmSpec.VerifyEmail
|
||||
realm.RememberMe = realmSpec.RememberMe
|
||||
|
||||
if realmSpec.SMTP != nil {
|
||||
smtp := map[string]string{}
|
||||
if realmSpec.SMTP.Auth {
|
||||
smtp["auth"] = "true"
|
||||
}
|
||||
|
||||
if realmSpec.SMTP.Secret != nil {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if realmSpec.SMTP.From != "" {
|
||||
smtp["from"] = realmSpec.SMTP.From
|
||||
}
|
||||
|
||||
realm.SMTPServer = &smtp
|
||||
}
|
||||
|
||||
//realm.AccessCodeLifespan = ""
|
||||
//realm.AccessCodeLifespanLogin = ""
|
||||
//realm.AccessCodeLifespanUserAction = ""
|
||||
//realm.AccessTokenLifespan = ""
|
||||
//realm.AccessTokenLifespanForImplicitFlow = ""
|
||||
//realm.AccountTheme = ""
|
||||
//realm.ActionTokenGeneratedByAdminLifespan = ""
|
||||
//realm.ActionTokenGeneratedByUserLifespan = ""
|
||||
//realm.AdminEventsDetailsEnabled = ""
|
||||
//realm.AdminEventsEnabled = ""
|
||||
//realm.AdminTheme = ""
|
||||
//realm.Attributes = ""
|
||||
//realm.AuthenticationFlows = ""
|
||||
//realm.AuthenticatorConfig = ""
|
||||
//realm.BrowserFlow = ""
|
||||
//realm.BrowserSecurityHeaders = ""
|
||||
//realm.BruteForceProtected = ""
|
||||
//realm.ClientAuthenticationFlow = ""
|
||||
//realm.ClientScopeMappings = ""
|
||||
//realm.ClientScopes = ""
|
||||
//realm.Clients = ""
|
||||
//realm.Components = ""
|
||||
//realm.DefaultDefaultClientScopes = ""
|
||||
//realm.DefaultGroups = ""
|
||||
//realm.DefaultLocale = ""
|
||||
//realm.DefaultOptionalClientScopes = ""
|
||||
//realm.DefaultRoles = ""
|
||||
//realm.DefaultSignatureAlgorithm = ""
|
||||
//realm.DirectGrantFlow = ""
|
||||
//realm.DockerAuthenticationFlow = ""
|
||||
//realm.EmailTheme = ""
|
||||
//realm.EnabledEventTypes = ""
|
||||
//realm.EventsEnabled = ""
|
||||
//realm.EventsExpiration = ""
|
||||
//realm.EventsListeners = ""
|
||||
//realm.FailureFactor = ""
|
||||
//realm.FederatedUsers = ""
|
||||
//realm.Groups = ""
|
||||
//realm.ID = ""
|
||||
//realm.IdentityProviderMappers = ""
|
||||
//realm.IdentityProviders = ""
|
||||
//realm.InternationalizationEnabled = ""
|
||||
//realm.KeycloakVersion = ""
|
||||
//realm.MaxDeltaTimeSeconds = ""
|
||||
//realm.MaxFailureWaitSeconds = ""
|
||||
//realm.MinimumQuickLoginWaitSeconds = ""
|
||||
//realm.NotBefore = ""
|
||||
//realm.OfflineSessionIdleTimeout = ""
|
||||
//realm.OfflineSessionMaxLifespan = ""
|
||||
//realm.OfflineSessionMaxLifespanEnabled = ""
|
||||
//realm.OtpPolicyAlgorithm = ""
|
||||
//realm.OtpPolicyDigits = ""
|
||||
//realm.OtpPolicyInitialCounter = ""
|
||||
//realm.OtpPolicyLookAheadWindow = ""
|
||||
//realm.OtpPolicyPeriod = ""
|
||||
//realm.OtpPolicyType = ""
|
||||
//realm.OtpSupportedApplications = ""
|
||||
//realm.PasswordPolicy = ""
|
||||
//realm.PermanentLockout = ""
|
||||
//realm.ProtocolMappers = ""
|
||||
//realm.QuickLoginCheckMilliSeconds = ""
|
||||
//realm.RefreshTokenMaxReuse = ""
|
||||
//realm.RegistrationFlow = ""
|
||||
//realm.RequiredActions = ""
|
||||
//realm.ResetCredentialsFlow = ""
|
||||
//realm.RevokeRefreshToken = ""
|
||||
//realm.Roles = ""
|
||||
//realm.ScopeMappings = ""
|
||||
//realm.SMTPServer = ""
|
||||
//realm.SslRequired = ""
|
||||
//realm.SsoSessionIdleTimeout = ""
|
||||
//realm.SsoSessionIdleTimeoutRememberMe = ""
|
||||
//realm.SsoSessionMaxLifespan = ""
|
||||
//realm.SsoSessionMaxLifespanRememberMe = ""
|
||||
//realm.SupportedLocales = ""
|
||||
//realm.UserFederationMappers = ""
|
||||
//realm.UserFederationProviders = ""
|
||||
//realm.UserManagedAccessAllowed = ""
|
||||
//realm.Users = ""
|
||||
//realm.WaitIncrementSeconds = ""
|
||||
|
||||
return realm, nil
|
||||
}
|
|
@ -19,6 +19,7 @@ package controllers
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Nerzal/gocloak/v7"
|
||||
"github.com/go-logr/logr"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
@ -55,29 +56,75 @@ func (r *KeycloakRealmReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
|||
|
||||
log.Info("reconciling")
|
||||
|
||||
// We get the information from the CRD
|
||||
var realm keycloakv1alpha1.KeycloakRealm
|
||||
if err := r.Get(ctx, req.NamespacedName, &realm); err != nil {
|
||||
if apierrs.IsNotFound(err) {
|
||||
log.Info("I would now unregister the realm")
|
||||
// Realm is already deleted via finalizer.
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if realm.Status.Available {
|
||||
// try to get existing realm
|
||||
log.Info("Would try to fetch the realm by its id.",
|
||||
"id", realm.Spec.RealmName)
|
||||
// if found {
|
||||
log.Info("will act like i found it, updating.")
|
||||
// update()
|
||||
if !realm.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
// is in the process of being deleted
|
||||
if containsString(realm.ObjectMeta.Finalizers, FinalizerName) {
|
||||
// our finalizer is present, so lets handle any external dependency
|
||||
|
||||
// We do not want to delete anything, so we just disable the realm.
|
||||
disabled := gocloak.RealmRepresentation{Realm: &realm.Spec.RealmName, Enabled: gocloak.BoolP(false)}
|
||||
err := r.Keycloak.UpdateRealm(ctx, disabled)
|
||||
if err != nil {
|
||||
// if fail to delete the external dependency here, return with error
|
||||
// so that it can be retried
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
// remove our finalizer from the list and update it.
|
||||
realm.ObjectMeta.Finalizers = removeString(realm.ObjectMeta.Finalizers, FinalizerName)
|
||||
if err := r.Update(ctx, &realm); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
log.Info("Deleted the realm")
|
||||
}
|
||||
|
||||
// done
|
||||
return ctrl.Result{}, nil
|
||||
// }
|
||||
}
|
||||
|
||||
log.Info("Would now create the realm.")
|
||||
// Its not being deleted, so we seize the moment to take ownership.
|
||||
if !containsString(realm.ObjectMeta.Finalizers, FinalizerName) {
|
||||
typeMeta := realm.TypeMeta
|
||||
realm.ObjectMeta.Finalizers = append(realm.ObjectMeta.Finalizers, FinalizerName)
|
||||
if err := r.Update(ctx, &realm); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
// restore the TypeMeta object as it is removed during Update, but need to be accessed later
|
||||
realm.TypeMeta = typeMeta
|
||||
}
|
||||
|
||||
// Convert Realm
|
||||
keycloakRealm, err := ConvertToRealm(realm)
|
||||
if err != nil {
|
||||
log.Error(err, "Could not convert realm")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
err = r.Keycloak.CreateRealm(ctx, keycloakRealm)
|
||||
if err != nil {
|
||||
// try updating instead
|
||||
err := r.Keycloak.UpdateRealm(ctx, keycloakRealm)
|
||||
if err != nil {
|
||||
log.Error(err, "Could not create/update realm")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
log.Info("Updated the realm")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
realm.Status.Available = true
|
||||
r.Status().Update(ctx, &realm)
|
||||
log.Info("Successfully created realm")
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
|
4
go.sum
4
go.sum
|
@ -45,8 +45,10 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko
|
|||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
|
@ -338,6 +340,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
|
@ -589,6 +592,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
Loading…
Reference in a new issue