func SyncState()

in lib/oathclients/clients.go [139:209]


func SyncState(httpClient *http.Client, hydraAdminURL string, clients map[string]*pb.Client, secrets map[string]string) (*pb.ClientState, error) {
	state := &pb.ClientState{
		Add:            make(map[string]*pb.Client),
		Update:         make(map[string]*pb.Client),
		UpdateDiff:     make(map[string]string),
		Remove:         make(map[string]*pb.Client),
		Unchanged:      make(map[string]*pb.Client),
		NoSecret:       make(map[string]*pb.Client),
		SecretMismatch: []string{},
	}
	cs, err := hydra.ListClients(httpClient, hydraAdminURL)
	if err != nil {
		return nil, err
	}

	// Populate existing Hydra clients by ClientID. As the logic handles
	// these clients, remove them from this map. Remaining items no longer
	// exist in the Federated Access component, so delete the from Hydra.
	removable := make(map[string]*hydraapi.Client)
	for _, c := range cs {
		removable[c.ClientID] = c
	}

	// Add clients to hydra.
	for n, cli := range clients {
		c := &pb.Client{}
		proto.Merge(c, cli)
		c.Ui = nil

		sec, ok := secrets[c.ClientId]
		if !ok {
			glog.Errorf("sync hydra clients: client %q has no secret, and will not be included in Hydra client list.", n)
			state.NoSecret[n] = c
			continue
		}

		hc, ok := removable[c.ClientId]
		if !ok {
			// Does not exist in hydra, so create.
			state.Add[n] = c
			continue
		}

		// Update an existing client if it has changed.
		fhc, hsec := fromHydraClient(hc)
		if cmp.Equal(fhc, c, protocmp.Transform(), cmpopts.EquateEmpty()) && hsec == sec {
			state.Unchanged[n] = c
		} else {
			state.Update[n] = c
			if sec != hsec {
				// Add the name of the client only, do not reveal the secrets in the state.
				state.SecretMismatch = append(state.SecretMismatch, n)
			}
			// Take the diff again without revealing the secrets.
			state.UpdateDiff[n] = cmp.Diff(fhc, c, protocmp.Transform(), cmpopts.EquateEmpty())
		}
		// Whether updated or unchanged above, remove it from the `removable` list to avoid removing the hydra client below.
		delete(removable, hc.ClientID)
	}

	// Remove remaining existing hydra clients on the `removable` list.
	for _, hc := range removable {
		c, _ := fromHydraClient(hc)
		state.Remove[hc.Name] = c
	}

	sort.Strings(state.SecretMismatch)
	msg := fmt.Sprintf("hydra clients status: add %d, update %d, remove %d, unchanged %d, no_secret %d", len(state.Add), len(state.Update), len(state.Remove), len(state.Unchanged), len(state.NoSecret))
	state.Status = httputils.NewStatus(codes.OK, msg).Proto()
	return state, nil
}