<commit_before>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package permission

import (
	"sort"

	"gopkg.in/check.v1"
)

func (s *S) TestNewRole(c *check.C) {
	r, err := NewRole("myrole", "app", "")
	c.Assert(err, check.IsNil)
	c.Assert(r.Name, check.Equals, "myrole")
	c.Assert(r.ContextType, check.Equals, CtxApp)
	_, err = NewRole("myrole", "global", "")
	c.Assert(err, check.Equals, ErrRoleAlreadyExists)
	_, err = NewRole("  ", "app", "")
	c.Assert(err, check.ErrorMatches, `invalid role name ""`)
	_, err = NewRole("myrole2", "invalid", "")
	c.Assert(err, check.ErrorMatches, `invalid context type "invalid"`)
}

func (s *S) TestListRoles(c *check.C) {
	r, err := NewRole("test", "app", "")
	c.Assert(err, check.IsNil)
	roles, err := ListRoles()
	c.Assert(err, check.IsNil)
	expected := []Role{{Name: "test", ContextType: "app", SchemeNames: []string{}, Events: []string{}}}
	c.Assert(roles, check.DeepEquals, expected)
	err = r.AddPermissions("app.deploy", "app.update")
	c.Assert(err, check.IsNil)
	r.SchemeNames = append(r.SchemeNames, "invalid")
	coll, err := rolesCollection()
	c.Assert(err, check.IsNil)
	defer coll.Close()
	err = coll.UpdateId(r.Name, r)
	c.Assert(err, check.IsNil)
	roles, err = ListRoles()
	expected = []Role{{Name: "test", ContextType: "app", Events: []string{}, SchemeNames: []string{
		"app.deploy", "app.update",
	}}}
	c.Assert(roles, check.DeepEquals, expected)
}

func (s *S) TestFindRole(c *check.C) {
	_, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	r, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(r.Name, check.Equals, "myrole")
	c.Assert(r.ContextType, check.Equals, CtxTeam)
	_, err = FindRole("something")
	c.Assert(err, check.Equals, ErrRoleNotFound)
}

func (s *S) TestRoleAddPermissions(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("app.update", "app.update.env.set")
	c.Assert(err, check.IsNil)
	sort.Strings(r.SchemeNames)
	expected := []string{
		"app.update",
		"app.update.env.set",
	}
	c.Assert(r.SchemeNames, check.DeepEquals, expected)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	sort.Strings(dbR.SchemeNames)
	c.Assert(dbR.SchemeNames, check.DeepEquals, expected)
}

func (s *S) TestRoleGlobalAddPermissions(c *check.C) {
	r, err := NewRole("myrole", "global", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("")
	c.Assert(err, check.ErrorMatches, "empty permission name")
	err = r.AddPermissions("*")
	c.Assert(err, check.IsNil)
	sort.Strings(r.SchemeNames)
	expected := []string{"*"}
	c.Assert(r.SchemeNames, check.DeepEquals, expected)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	sort.Strings(dbR.SchemeNames)
	c.Assert(dbR.SchemeNames, check.DeepEquals, expected)
	err = r.AddPermissions("app.deploy")
	c.Assert(err, check.IsNil)
}

func (s *S) TestRoleAddPermissionsInvalid(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("app.update.env.set.nih")
	c.Assert(err, check.ErrorMatches, `permission named "app.update.env.set.nih" not found`)
	err = r.AddPermissions("node.create")
	c.Assert(err, check.ErrorMatches, `permission "node.create" not allowed with context of type "team"`)
}

func (s *S) TestRemovePermissions(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("app.update", "app.update.env.set")
	c.Assert(err, check.IsNil)
	err = r.RemovePermissions("app.update")
	c.Assert(err, check.IsNil)
	expected := []string{"app.update.env.set"}
	c.Assert(r.SchemeNames, check.DeepEquals, expected)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.SchemeNames, check.DeepEquals, expected)
}

func (s *S) TestDestroyRole(c *check.C) {
	_, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = DestroyRole("myrole")
	c.Assert(err, check.IsNil)
	err = DestroyRole("myrole")
	c.Assert(err, check.Equals, ErrRoleNotFound)
}

func (s *S) TestPermissionsFor(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	perms := r.PermissionsFor("something")
	c.Assert(perms, check.DeepEquals, []Permission{})
	err = r.AddPermissions("app.update", "app.update.env.set")
	c.Assert(err, check.IsNil)
	expected := []Permission{
		{Scheme: PermissionRegistry.get("app.update"), Context: PermissionContext{CtxType: CtxTeam, Value: "something"}},
		{Scheme: PermissionRegistry.get("app.update.env.set"), Context: PermissionContext{CtxType: CtxTeam, Value: "something"}},
	}
	perms = r.PermissionsFor("something")
	c.Assert(perms, check.DeepEquals, expected)
	r.SchemeNames = append(r.SchemeNames, "invalidxxx")
	perms = r.PermissionsFor("something")
	c.Assert(perms, check.DeepEquals, expected)
}

func (s *S) TestRoleAddEvent(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	c.Assert(r.Events, check.DeepEquals, []string{RoleEventTeamCreate.name})
	err = r.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	c.Assert(r.Events, check.DeepEquals, []string{RoleEventTeamCreate.name})
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.Events, check.DeepEquals, []string{RoleEventTeamCreate.name})
}

func (s *S) TestRoleRemoveEvent(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	err = dbR.RemoveEvent("team-create")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.Events, check.DeepEquals, []string{})
	dbR, err = FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.Events, check.DeepEquals, []string{})
}

func (s *S) TestListRolesWithEvents(c *check.C) {
	_, err := NewRole("myrole1", "team", "")
	c.Assert(err, check.IsNil)
	r2, err := NewRole("myrole2", "team", "")
	c.Assert(err, check.IsNil)
	r3, err := NewRole("myrole3", "team", "")
	c.Assert(err, check.IsNil)
	err = r2.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	err = r3.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	roles, err := ListRolesWithEvents()
	c.Assert(err, check.IsNil)
	var names []string
	for _, r := range roles {
		names = append(names, r.Name)
	}
	sort.Strings(names)
	c.Assert(names, check.DeepEquals, []string{"myrole2", "myrole3"})
}

func (s *S) TestListRolesForEvent(c *check.C) {
	_, err := NewRole("myrole1", "team", "")
	c.Assert(err, check.IsNil)
	r2, err := NewRole("myrole2", "team", "")
	c.Assert(err, check.IsNil)
	r3, err := NewRole("myrole3", "global", "")
	c.Assert(err, check.IsNil)
	err = r2.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	err = r3.AddEvent("user-create")
	c.Assert(err, check.IsNil)
	roles, err := ListRolesForEvent(RoleEventTeamCreate)
	c.Assert(err, check.IsNil)
	c.Assert(roles, check.HasLen, 1)
	c.Assert(roles[0].Name, check.Equals, "myrole2")
}
<commit_msg>permission: fix test<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package permission

import (
	"sort"

	"gopkg.in/check.v1"
)

func (s *S) TestNewRole(c *check.C) {
	r, err := NewRole("myrole", "app", "")
	c.Assert(err, check.IsNil)
	c.Assert(r.Name, check.Equals, "myrole")
	c.Assert(r.ContextType, check.Equals, CtxApp)
	_, err = NewRole("myrole", "global", "")
	c.Assert(err, check.Equals, ErrRoleAlreadyExists)
	_, err = NewRole("  ", "app", "")
	c.Assert(err, check.ErrorMatches, "invalid role name")
	_, err = NewRole("myrole2", "invalid", "")
	c.Assert(err, check.ErrorMatches, `invalid context type "invalid"`)
}

func (s *S) TestListRoles(c *check.C) {
	r, err := NewRole("test", "app", "")
	c.Assert(err, check.IsNil)
	roles, err := ListRoles()
	c.Assert(err, check.IsNil)
	expected := []Role{{Name: "test", ContextType: "app", SchemeNames: []string{}, Events: []string{}}}
	c.Assert(roles, check.DeepEquals, expected)
	err = r.AddPermissions("app.deploy", "app.update")
	c.Assert(err, check.IsNil)
	r.SchemeNames = append(r.SchemeNames, "invalid")
	coll, err := rolesCollection()
	c.Assert(err, check.IsNil)
	defer coll.Close()
	err = coll.UpdateId(r.Name, r)
	c.Assert(err, check.IsNil)
	roles, err = ListRoles()
	expected = []Role{{Name: "test", ContextType: "app", Events: []string{}, SchemeNames: []string{
		"app.deploy", "app.update",
	}}}
	c.Assert(roles, check.DeepEquals, expected)
}

func (s *S) TestFindRole(c *check.C) {
	_, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	r, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(r.Name, check.Equals, "myrole")
	c.Assert(r.ContextType, check.Equals, CtxTeam)
	_, err = FindRole("something")
	c.Assert(err, check.Equals, ErrRoleNotFound)
}

func (s *S) TestRoleAddPermissions(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("app.update", "app.update.env.set")
	c.Assert(err, check.IsNil)
	sort.Strings(r.SchemeNames)
	expected := []string{
		"app.update",
		"app.update.env.set",
	}
	c.Assert(r.SchemeNames, check.DeepEquals, expected)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	sort.Strings(dbR.SchemeNames)
	c.Assert(dbR.SchemeNames, check.DeepEquals, expected)
}

func (s *S) TestRoleGlobalAddPermissions(c *check.C) {
	r, err := NewRole("myrole", "global", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("")
	c.Assert(err, check.ErrorMatches, "empty permission name")
	err = r.AddPermissions("*")
	c.Assert(err, check.IsNil)
	sort.Strings(r.SchemeNames)
	expected := []string{"*"}
	c.Assert(r.SchemeNames, check.DeepEquals, expected)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	sort.Strings(dbR.SchemeNames)
	c.Assert(dbR.SchemeNames, check.DeepEquals, expected)
	err = r.AddPermissions("app.deploy")
	c.Assert(err, check.IsNil)
}

func (s *S) TestRoleAddPermissionsInvalid(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("app.update.env.set.nih")
	c.Assert(err, check.ErrorMatches, `permission named "app.update.env.set.nih" not found`)
	err = r.AddPermissions("node.create")
	c.Assert(err, check.ErrorMatches, `permission "node.create" not allowed with context of type "team"`)
}

func (s *S) TestRemovePermissions(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddPermissions("app.update", "app.update.env.set")
	c.Assert(err, check.IsNil)
	err = r.RemovePermissions("app.update")
	c.Assert(err, check.IsNil)
	expected := []string{"app.update.env.set"}
	c.Assert(r.SchemeNames, check.DeepEquals, expected)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.SchemeNames, check.DeepEquals, expected)
}

func (s *S) TestDestroyRole(c *check.C) {
	_, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = DestroyRole("myrole")
	c.Assert(err, check.IsNil)
	err = DestroyRole("myrole")
	c.Assert(err, check.Equals, ErrRoleNotFound)
}

func (s *S) TestPermissionsFor(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	perms := r.PermissionsFor("something")
	c.Assert(perms, check.DeepEquals, []Permission{})
	err = r.AddPermissions("app.update", "app.update.env.set")
	c.Assert(err, check.IsNil)
	expected := []Permission{
		{Scheme: PermissionRegistry.get("app.update"), Context: PermissionContext{CtxType: CtxTeam, Value: "something"}},
		{Scheme: PermissionRegistry.get("app.update.env.set"), Context: PermissionContext{CtxType: CtxTeam, Value: "something"}},
	}
	perms = r.PermissionsFor("something")
	c.Assert(perms, check.DeepEquals, expected)
	r.SchemeNames = append(r.SchemeNames, "invalidxxx")
	perms = r.PermissionsFor("something")
	c.Assert(perms, check.DeepEquals, expected)
}

func (s *S) TestRoleAddEvent(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	c.Assert(r.Events, check.DeepEquals, []string{RoleEventTeamCreate.name})
	err = r.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	c.Assert(r.Events, check.DeepEquals, []string{RoleEventTeamCreate.name})
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.Events, check.DeepEquals, []string{RoleEventTeamCreate.name})
}

func (s *S) TestRoleRemoveEvent(c *check.C) {
	r, err := NewRole("myrole", "team", "")
	c.Assert(err, check.IsNil)
	err = r.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	dbR, err := FindRole("myrole")
	c.Assert(err, check.IsNil)
	err = dbR.RemoveEvent("team-create")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.Events, check.DeepEquals, []string{})
	dbR, err = FindRole("myrole")
	c.Assert(err, check.IsNil)
	c.Assert(dbR.Events, check.DeepEquals, []string{})
}

func (s *S) TestListRolesWithEvents(c *check.C) {
	_, err := NewRole("myrole1", "team", "")
	c.Assert(err, check.IsNil)
	r2, err := NewRole("myrole2", "team", "")
	c.Assert(err, check.IsNil)
	r3, err := NewRole("myrole3", "team", "")
	c.Assert(err, check.IsNil)
	err = r2.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	err = r3.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	roles, err := ListRolesWithEvents()
	c.Assert(err, check.IsNil)
	var names []string
	for _, r := range roles {
		names = append(names, r.Name)
	}
	sort.Strings(names)
	c.Assert(names, check.DeepEquals, []string{"myrole2", "myrole3"})
}

func (s *S) TestListRolesForEvent(c *check.C) {
	_, err := NewRole("myrole1", "team", "")
	c.Assert(err, check.IsNil)
	r2, err := NewRole("myrole2", "team", "")
	c.Assert(err, check.IsNil)
	r3, err := NewRole("myrole3", "global", "")
	c.Assert(err, check.IsNil)
	err = r2.AddEvent("team-create")
	c.Assert(err, check.IsNil)
	err = r3.AddEvent("user-create")
	c.Assert(err, check.IsNil)
	roles, err := ListRolesForEvent(RoleEventTeamCreate)
	c.Assert(err, check.IsNil)
	c.Assert(roles, check.HasLen, 1)
	c.Assert(roles[0].Name, check.Equals, "myrole2")
}
<|endoftext|>


<commit_before>/*
Copyright 2022 The Tekton Authors

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 tektonaddon

import (
	"context"
	"os"
	"path/filepath"
	"strings"

	occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"

	routev1 "github.com/openshift/api/route/v1"
	"github.com/openshift/client-go/route/clientset/versioned/scheme"
	"github.com/tektoncd/operator/pkg/reconciler/openshift"
	"github.com/tektoncd/operator/pkg/reconciler/shared/hash"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/yaml"

	mf "github.com/manifestival/manifestival"
	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
	"github.com/tektoncd/operator/pkg/reconciler/common"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const pacRuntimeLabel = "pipelinesascode.openshift.io/runtime"

var configmapTemplate = `apiVersion: v1
kind: ConfigMap
metadata:
  name: pipelines-as-code-template
  labels:
    app.kubernetes.io/part-of: pipelines-as-code
data:
  template: ""`

var pacLS = metav1.LabelSelector{
	MatchLabels: map[string]string{
		v1alpha1.InstallerSetType: PACInstallerSet,
	},
}

func (r *Reconciler) EnsurePipelinesAsCode(ctx context.Context, ta *v1alpha1.TektonAddon) error {

	pacLabelSelector, err := common.LabelSelector(pacLS)
	if err != nil {
		return err
	}

	if *ta.Spec.EnablePAC {
		exist, currentTIS, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, pacLabelSelector)
		if err != nil {
			return err
		}
		if !exist {
			return r.ensurePAC(ctx, ta)
		}

		expectedHash, err := hash.Compute(ta.Spec)
		if err != nil {
			return err
		}

		hashOnTIS := currentTIS.Annotations[v1alpha1.LastAppliedHashKey]
		if expectedHash != hashOnTIS {
			updatedManifest, err := r.getManifest(ctx, ta)
			if err != nil {
				return err
			}
			currentTIS.Spec.Manifests = updatedManifest.Resources()
			currentTIS.Annotations[v1alpha1.LastAppliedHashKey] = expectedHash

			if _, err = r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
				Update(ctx, currentTIS, metav1.UpdateOptions{}); err != nil {
				return err
			}
		}

		return r.updateControllerURL(ta)

	} else {
		// if disabled then delete the installer Set if exist
		if err := r.deleteInstallerSet(ctx, pacLabelSelector); err != nil {
			return err
		}
	}
	return nil
}

func (r *Reconciler) updateControllerURL(ta *v1alpha1.TektonAddon) error {
	var err error
	pacManifest := mf.Manifest{
		Client: r.manifest.Client,
	}

	koDataDir := os.Getenv(common.KoEnvKey)
	pacLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code")
	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
		return err
	}
	pacManifest, err = pacManifest.Transform(mf.InjectNamespace(ta.Spec.TargetNamespace))
	if err != nil {
		return err
	}

	route, err := getControllerRouteHost(&pacManifest)
	if err != nil {
		return err
	}
	if route == "" {
		return v1alpha1.RECONCILE_AGAIN_ERR
	}

	if err := updateInfoConfigMap(route, &pacManifest); err != nil {
		return err
	}
	return nil
}

func (r *Reconciler) ensurePAC(ctx context.Context, ta *v1alpha1.TektonAddon) error {
	pacManifest, err := r.getManifest(ctx, ta)
	if err != nil {
		return err
	}

	if err := createInstallerSet(ctx, r.operatorClientSet, ta, *pacManifest, r.operatorVersion,
		PACInstallerSet, "addon-pac"); err != nil {
		return err
	}

	return nil
}

func (r *Reconciler) getManifest(ctx context.Context, ta *v1alpha1.TektonAddon) (*mf.Manifest, error) {
	pacManifest := mf.Manifest{}

	// core manifest
	koDataDir := os.Getenv(common.KoEnvKey)
	pacLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code")
	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
		return nil, err
	}

	if err := fetchPRTemplates(&pacManifest); err != nil {
		return nil, err
	}

	// installerSet adds it's owner as namespace's owner
	// so deleting tekton addon deletes target namespace too
	// to skip it we filter out namespace
	pacManifest = pacManifest.Filter(mf.Not(mf.ByKind("Namespace")))

	images := common.ToLowerCaseKeys(common.ImagesFromEnv(common.PacImagePrefix))
	// Run transformers
	tfs := []mf.Transformer{
		common.InjectOperandNameLabelOverwriteExisting(openshift.OperandOpenShiftPipelineAsCode),
		common.DeploymentImages(images),
		common.AddConfiguration(ta.Spec.Config),
		common.ApplyProxySettings,
		occommon.ApplyCABundles,
	}

	if err := r.addonTransform(ctx, &pacManifest, ta, tfs...); err != nil {
		return nil, err
	}

	return &pacManifest, nil
}

func fetchPRTemplates(manifest *mf.Manifest) error {
	prManifests := mf.Manifest{}
	koDataDir := os.Getenv(common.KoEnvKey)
	templateLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code-templates")
	if err := common.AppendManifest(&prManifests, templateLocation); err != nil {
		return err
	}

	cmManifest, err := pipelineRunToConfigMapConverter(&prManifests)
	if err != nil {
		return err
	}
	*manifest = manifest.Append(*cmManifest)
	return nil
}

func pipelineRunToConfigMapConverter(prManifests *mf.Manifest) (*mf.Manifest, error) {
	cm := &v1.ConfigMap{}
	err := yaml.Unmarshal([]byte(configmapTemplate), cm)
	if err != nil {
		return nil, err
	}

	var temp []unstructured.Unstructured
	for _, res := range prManifests.Resources() {
		if res.GetKind() != "PipelineRun" {
			temp = append(temp, res)
			continue
		}

		data, err := yaml.Marshal(res.Object)
		if err != nil {
			return nil, err
		}

		// set pipelineRun
		cm.Data["template"] = string(data)

		// set metadata
		prname := res.GetName()
		cm.SetName("pipelines-as-code-" + prname)
		cm.Labels[pacRuntimeLabel] = strings.TrimPrefix(prname, "pipelinerun-")

		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
		if err != nil {
			return nil, err
		}

		temp = append(temp, unstructured.Unstructured{Object: unstrObj})
	}
	manifest, _ := mf.ManifestFrom(mf.Slice(temp))
	return &manifest, nil
}

func getControllerRouteHost(manifest *mf.Manifest) (string, error) {
	var hostUrl string
	for _, r := range manifest.Filter(mf.ByKind("Route")).Resources() {
		u, err := manifest.Client.Get(&r)
		if err != nil {
			return "", err
		}
		if u.GetName() == "pipelines-as-code-controller" {
			route := &routev1.Route{}
			if err := scheme.Scheme.Convert(u, route, nil); err != nil {
				return "", err
			}
			hostUrl = route.Spec.Host
		}
	}
	return hostUrl, nil
}

func updateInfoConfigMap(route string, pacManifest *mf.Manifest) error {
	for _, r := range pacManifest.Filter(mf.ByKind("ConfigMap")).Resources() {
		if r.GetName() != "pipelines-as-code-info" {
			continue
		}
		u, err := pacManifest.Client.Get(&r)
		if err != nil {
			return err
		}
		cm := &v1.ConfigMap{}
		err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cm)
		if err != nil {
			return err
		}

		// set controller url
		if cm.Data["controller-url"] != "" {
			return nil
		}

		cm.Data["controller-url"] = "https://" + route

		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
		if err != nil {
			return err
		}
		u.SetUnstructuredContent(unstrObj)

		err = pacManifest.Client.Update(u)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>PAC: creates pipelinerun templates in openshift namespace<commit_after>/*
Copyright 2022 The Tekton Authors

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 tektonaddon

import (
	"context"
	"os"
	"path/filepath"
	"strings"

	occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"

	routev1 "github.com/openshift/api/route/v1"
	"github.com/openshift/client-go/route/clientset/versioned/scheme"
	"github.com/tektoncd/operator/pkg/reconciler/openshift"
	"github.com/tektoncd/operator/pkg/reconciler/shared/hash"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/yaml"

	mf "github.com/manifestival/manifestival"
	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
	"github.com/tektoncd/operator/pkg/reconciler/common"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	pacRuntimeLabel = "pipelinesascode.openshift.io/runtime"
	openshiftNS     = "openshift"
)

var configmapTemplate = `apiVersion: v1
kind: ConfigMap
metadata:
  name: pipelines-as-code-template
  labels:
    app.kubernetes.io/part-of: pipelines-as-code
data:
  template: ""`

var pacLS = metav1.LabelSelector{
	MatchLabels: map[string]string{
		v1alpha1.InstallerSetType: PACInstallerSet,
	},
}

func (r *Reconciler) EnsurePipelinesAsCode(ctx context.Context, ta *v1alpha1.TektonAddon) error {

	pacLabelSelector, err := common.LabelSelector(pacLS)
	if err != nil {
		return err
	}

	if *ta.Spec.EnablePAC {
		exist, currentTIS, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, pacLabelSelector)
		if err != nil {
			return err
		}
		if !exist {
			return r.ensurePAC(ctx, ta)
		}

		expectedHash, err := hash.Compute(ta.Spec)
		if err != nil {
			return err
		}

		hashOnTIS := currentTIS.Annotations[v1alpha1.LastAppliedHashKey]
		if expectedHash != hashOnTIS {
			updatedManifest, err := r.getManifest(ctx, ta)
			if err != nil {
				return err
			}
			currentTIS.Spec.Manifests = updatedManifest.Resources()
			currentTIS.Annotations[v1alpha1.LastAppliedHashKey] = expectedHash

			if _, err = r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
				Update(ctx, currentTIS, metav1.UpdateOptions{}); err != nil {
				return err
			}
		}

		return r.updateControllerURL(ta)

	} else {
		// if disabled then delete the installer Set if exist
		if err := r.deleteInstallerSet(ctx, pacLabelSelector); err != nil {
			return err
		}
	}
	return nil
}

func (r *Reconciler) updateControllerURL(ta *v1alpha1.TektonAddon) error {
	var err error
	pacManifest := mf.Manifest{
		Client: r.manifest.Client,
	}

	koDataDir := os.Getenv(common.KoEnvKey)
	pacLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code")
	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
		return err
	}
	pacManifest, err = pacManifest.Transform(mf.InjectNamespace(ta.Spec.TargetNamespace))
	if err != nil {
		return err
	}

	route, err := getControllerRouteHost(&pacManifest)
	if err != nil {
		return err
	}
	if route == "" {
		return v1alpha1.RECONCILE_AGAIN_ERR
	}

	if err := updateInfoConfigMap(route, &pacManifest); err != nil {
		return err
	}
	return nil
}

func (r *Reconciler) ensurePAC(ctx context.Context, ta *v1alpha1.TektonAddon) error {
	pacManifest, err := r.getManifest(ctx, ta)
	if err != nil {
		return err
	}

	if err := createInstallerSet(ctx, r.operatorClientSet, ta, *pacManifest, r.operatorVersion,
		PACInstallerSet, "addon-pac"); err != nil {
		return err
	}

	return nil
}

func (r *Reconciler) getManifest(ctx context.Context, ta *v1alpha1.TektonAddon) (*mf.Manifest, error) {
	pacManifest := mf.Manifest{}

	// core manifest
	koDataDir := os.Getenv(common.KoEnvKey)
	pacLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code")
	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
		return nil, err
	}

	prTemplates := mf.Manifest{}
	if err := fetchPRTemplates(&prTemplates); err != nil {
		return nil, err
	}
	var err error
	prTemplates, err = prTemplates.Transform(mf.InjectNamespace(openshiftNS))
	if err != nil {
		return nil, err
	}

	// installerSet adds it's owner as namespace's owner
	// so deleting tekton addon deletes target namespace too
	// to skip it we filter out namespace
	pacManifest = pacManifest.Filter(mf.Not(mf.ByKind("Namespace")))

	images := common.ToLowerCaseKeys(common.ImagesFromEnv(common.PacImagePrefix))
	// Run transformers
	tfs := []mf.Transformer{
		common.InjectOperandNameLabelOverwriteExisting(openshift.OperandOpenShiftPipelineAsCode),
		common.DeploymentImages(images),
		common.AddConfiguration(ta.Spec.Config),
		common.ApplyProxySettings,
		occommon.ApplyCABundles,
	}

	if err := r.addonTransform(ctx, &pacManifest, ta, tfs...); err != nil {
		return nil, err
	}

	pacManifest = pacManifest.Append(prTemplates)

	return &pacManifest, nil
}

func fetchPRTemplates(manifest *mf.Manifest) error {
	prManifests := mf.Manifest{}
	koDataDir := os.Getenv(common.KoEnvKey)
	templateLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code-templates")
	if err := common.AppendManifest(&prManifests, templateLocation); err != nil {
		return err
	}

	cmManifest, err := pipelineRunToConfigMapConverter(&prManifests)
	if err != nil {
		return err
	}
	*manifest = manifest.Append(*cmManifest)
	return nil
}

func pipelineRunToConfigMapConverter(prManifests *mf.Manifest) (*mf.Manifest, error) {
	cm := &v1.ConfigMap{}
	err := yaml.Unmarshal([]byte(configmapTemplate), cm)
	if err != nil {
		return nil, err
	}

	var temp []unstructured.Unstructured
	for _, res := range prManifests.Resources() {
		if res.GetKind() != "PipelineRun" {
			temp = append(temp, res)
			continue
		}

		data, err := yaml.Marshal(res.Object)
		if err != nil {
			return nil, err
		}

		// set pipelineRun
		cm.Data["template"] = string(data)

		// set metadata
		prname := res.GetName()
		cm.SetName("pipelines-as-code-" + prname)
		cm.Labels[pacRuntimeLabel] = strings.TrimPrefix(prname, "pipelinerun-")

		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
		if err != nil {
			return nil, err
		}

		temp = append(temp, unstructured.Unstructured{Object: unstrObj})
	}
	manifest, _ := mf.ManifestFrom(mf.Slice(temp))
	return &manifest, nil
}

func getControllerRouteHost(manifest *mf.Manifest) (string, error) {
	var hostUrl string
	for _, r := range manifest.Filter(mf.ByKind("Route")).Resources() {
		u, err := manifest.Client.Get(&r)
		if err != nil {
			return "", err
		}
		if u.GetName() == "pipelines-as-code-controller" {
			route := &routev1.Route{}
			if err := scheme.Scheme.Convert(u, route, nil); err != nil {
				return "", err
			}
			hostUrl = route.Spec.Host
		}
	}
	return hostUrl, nil
}

func updateInfoConfigMap(route string, pacManifest *mf.Manifest) error {
	for _, r := range pacManifest.Filter(mf.ByKind("ConfigMap")).Resources() {
		if r.GetName() != "pipelines-as-code-info" {
			continue
		}
		u, err := pacManifest.Client.Get(&r)
		if err != nil {
			return err
		}
		cm := &v1.ConfigMap{}
		err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cm)
		if err != nil {
			return err
		}

		// set controller url
		if cm.Data["controller-url"] != "" {
			return nil
		}

		cm.Data["controller-url"] = "https://" + route

		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
		if err != nil {
			return err
		}
		u.SetUnstructuredContent(unstrObj)

		err = pacManifest.Client.Update(u)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package aztokenprovider

import (
	"context"
	"crypto/sha256"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
)

var (
	azureTokenCache = NewConcurrentTokenCache()
)

type AzureTokenProvider interface {
	GetAccessToken(ctx context.Context, scopes []string) (string, error)
}

type tokenProviderImpl struct {
	tokenRetriever TokenRetriever
}

func NewAzureAccessTokenProvider(cfg *setting.Cfg, credentials azcredentials.AzureCredentials) (AzureTokenProvider, error) {
	if cfg == nil {
		err := fmt.Errorf("parameter 'cfg' cannot be nil")
		return nil, err
	}
	if credentials == nil {
		err := fmt.Errorf("parameter 'credentials' cannot be nil")
		return nil, err
	}

	var tokenRetriever TokenRetriever

	switch c := credentials.(type) {
	case *azcredentials.AzureManagedIdentityCredentials:
		if !cfg.Azure.ManagedIdentityEnabled {
			err := fmt.Errorf("managed identity authentication is not enabled in Grafana config")
			return nil, err
		} else {
			tokenRetriever = getManagedIdentityTokenRetriever(cfg, c)
		}
	case *azcredentials.AzureClientSecretCredentials:
		tokenRetriever = getClientSecretTokenRetriever(c)
	default:
		err := fmt.Errorf("credentials of type '%s' not supported by authentication provider", c.AzureAuthType())
		return nil, err
	}

	tokenProvider := &tokenProviderImpl{
		tokenRetriever: tokenRetriever,
	}

	return tokenProvider, nil
}

func (provider *tokenProviderImpl) GetAccessToken(ctx context.Context, scopes []string) (string, error) {
	if ctx == nil {
		err := fmt.Errorf("parameter 'ctx' cannot be nil")
		return "", err
	}
	if scopes == nil {
		err := fmt.Errorf("parameter 'scopes' cannot be nil")
		return "", err
	}

	accessToken, err := azureTokenCache.GetAccessToken(ctx, provider.tokenRetriever, scopes)
	if err != nil {
		return "", err
	}
	return accessToken, nil
}

func getManagedIdentityTokenRetriever(cfg *setting.Cfg, credentials *azcredentials.AzureManagedIdentityCredentials) TokenRetriever {
	var clientId string
	if credentials.ClientId != "" {
		clientId = credentials.ClientId
	} else {
		clientId = cfg.Azure.ManagedIdentityClientId
	}
	return &managedIdentityTokenRetriever{
		clientId: clientId,
	}
}

func getClientSecretTokenRetriever(credentials *azcredentials.AzureClientSecretCredentials) TokenRetriever {
	var authority string
	if credentials.Authority != "" {
		authority = credentials.Authority
	} else {
		authority = resolveAuthorityForCloud(credentials.AzureCloud)
	}
	return &clientSecretTokenRetriever{
		authority:    authority,
		tenantId:     credentials.TenantId,
		clientId:     credentials.ClientId,
		clientSecret: credentials.ClientSecret,
	}
}

func resolveAuthorityForCloud(cloudName string) string {
	// Known Azure clouds
	switch cloudName {
	case setting.AzurePublic:
		return azidentity.AzurePublicCloud
	case setting.AzureChina:
		return azidentity.AzureChina
	case setting.AzureUSGovernment:
		return azidentity.AzureGovernment
	case setting.AzureGermany:
		return azidentity.AzureGermany
	default:
		return ""
	}
}

type managedIdentityTokenRetriever struct {
	clientId   string
	credential azcore.TokenCredential
}

func (c *managedIdentityTokenRetriever) GetCacheKey() string {
	clientId := c.clientId
	if clientId == "" {
		clientId = "system"
	}
	return fmt.Sprintf("azure|msi|%s", clientId)
}

func (c *managedIdentityTokenRetriever) Init() error {
	if credential, err := azidentity.NewManagedIdentityCredential(c.clientId, nil); err != nil {
		return err
	} else {
		c.credential = credential
		return nil
	}
}

func (c *managedIdentityTokenRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) {
	accessToken, err := c.credential.GetToken(ctx, azcore.TokenRequestOptions{Scopes: scopes})
	if err != nil {
		return nil, err
	}

	return &AccessToken{Token: accessToken.Token, ExpiresOn: accessToken.ExpiresOn}, nil
}

type clientSecretTokenRetriever struct {
	authority    string
	tenantId     string
	clientId     string
	clientSecret string
	credential   azcore.TokenCredential
}

func (c *clientSecretTokenRetriever) GetCacheKey() string {
	return fmt.Sprintf("azure|clientsecret|%s|%s|%s|%s", c.authority, c.tenantId, c.clientId, hashSecret(c.clientSecret))
}

func (c *clientSecretTokenRetriever) Init() error {
	options := &azidentity.ClientSecretCredentialOptions{AuthorityHost: c.authority}
	if credential, err := azidentity.NewClientSecretCredential(c.tenantId, c.clientId, c.clientSecret, options); err != nil {
		return err
	} else {
		c.credential = credential
		return nil
	}
}

func (c *clientSecretTokenRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) {
	accessToken, err := c.credential.GetToken(ctx, azcore.TokenRequestOptions{Scopes: scopes})
	if err != nil {
		return nil, err
	}

	return &AccessToken{Token: accessToken.Token, ExpiresOn: accessToken.ExpiresOn}, nil
}

func hashSecret(secret string) string {
	hash := sha256.New()
	_, _ = hash.Write([]byte(secret))
	return fmt.Sprintf("%x", hash.Sum(nil))
}
<commit_msg>Fix scopes mutation by cloning original array (#37981)<commit_after>package aztokenprovider

import (
	"context"
	"crypto/sha256"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
)

var (
	azureTokenCache = NewConcurrentTokenCache()
)

type AzureTokenProvider interface {
	GetAccessToken(ctx context.Context, scopes []string) (string, error)
}

type tokenProviderImpl struct {
	tokenRetriever TokenRetriever
}

func NewAzureAccessTokenProvider(cfg *setting.Cfg, credentials azcredentials.AzureCredentials) (AzureTokenProvider, error) {
	if cfg == nil {
		err := fmt.Errorf("parameter 'cfg' cannot be nil")
		return nil, err
	}
	if credentials == nil {
		err := fmt.Errorf("parameter 'credentials' cannot be nil")
		return nil, err
	}

	var tokenRetriever TokenRetriever

	switch c := credentials.(type) {
	case *azcredentials.AzureManagedIdentityCredentials:
		if !cfg.Azure.ManagedIdentityEnabled {
			err := fmt.Errorf("managed identity authentication is not enabled in Grafana config")
			return nil, err
		} else {
			tokenRetriever = getManagedIdentityTokenRetriever(cfg, c)
		}
	case *azcredentials.AzureClientSecretCredentials:
		tokenRetriever = getClientSecretTokenRetriever(c)
	default:
		err := fmt.Errorf("credentials of type '%s' not supported by authentication provider", c.AzureAuthType())
		return nil, err
	}

	tokenProvider := &tokenProviderImpl{
		tokenRetriever: tokenRetriever,
	}

	return tokenProvider, nil
}

func (provider *tokenProviderImpl) GetAccessToken(ctx context.Context, scopes []string) (string, error) {
	if ctx == nil {
		err := fmt.Errorf("parameter 'ctx' cannot be nil")
		return "", err
	}
	if scopes == nil {
		err := fmt.Errorf("parameter 'scopes' cannot be nil")
		return "", err
	}

	accessToken, err := azureTokenCache.GetAccessToken(ctx, provider.tokenRetriever, scopes)
	if err != nil {
		return "", err
	}
	return accessToken, nil
}

func getManagedIdentityTokenRetriever(cfg *setting.Cfg, credentials *azcredentials.AzureManagedIdentityCredentials) TokenRetriever {
	var clientId string
	if credentials.ClientId != "" {
		clientId = credentials.ClientId
	} else {
		clientId = cfg.Azure.ManagedIdentityClientId
	}
	return &managedIdentityTokenRetriever{
		clientId: clientId,
	}
}

func getClientSecretTokenRetriever(credentials *azcredentials.AzureClientSecretCredentials) TokenRetriever {
	var authority string
	if credentials.Authority != "" {
		authority = credentials.Authority
	} else {
		authority = resolveAuthorityForCloud(credentials.AzureCloud)
	}
	return &clientSecretTokenRetriever{
		authority:    authority,
		tenantId:     credentials.TenantId,
		clientId:     credentials.ClientId,
		clientSecret: credentials.ClientSecret,
	}
}

func resolveAuthorityForCloud(cloudName string) string {
	// Known Azure clouds
	switch cloudName {
	case setting.AzurePublic:
		return azidentity.AzurePublicCloud
	case setting.AzureChina:
		return azidentity.AzureChina
	case setting.AzureUSGovernment:
		return azidentity.AzureGovernment
	case setting.AzureGermany:
		return azidentity.AzureGermany
	default:
		return ""
	}
}

type managedIdentityTokenRetriever struct {
	clientId   string
	credential azcore.TokenCredential
}

func (c *managedIdentityTokenRetriever) GetCacheKey() string {
	clientId := c.clientId
	if clientId == "" {
		clientId = "system"
	}
	return fmt.Sprintf("azure|msi|%s", clientId)
}

func (c *managedIdentityTokenRetriever) Init() error {
	if credential, err := azidentity.NewManagedIdentityCredential(c.clientId, nil); err != nil {
		return err
	} else {
		c.credential = credential
		return nil
	}
}

func (c *managedIdentityTokenRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) {
	// Workaround for a bug in Azure SDK which mutates the passed array of scopes
	// See details https://github.com/Azure/azure-sdk-for-go/issues/15308
	arr := make([]string, len(scopes))
	copy(arr, scopes)
	scopes = arr

	accessToken, err := c.credential.GetToken(ctx, azcore.TokenRequestOptions{Scopes: scopes})
	if err != nil {
		return nil, err
	}

	return &AccessToken{Token: accessToken.Token, ExpiresOn: accessToken.ExpiresOn}, nil
}

type clientSecretTokenRetriever struct {
	authority    string
	tenantId     string
	clientId     string
	clientSecret string
	credential   azcore.TokenCredential
}

func (c *clientSecretTokenRetriever) GetCacheKey() string {
	return fmt.Sprintf("azure|clientsecret|%s|%s|%s|%s", c.authority, c.tenantId, c.clientId, hashSecret(c.clientSecret))
}

func (c *clientSecretTokenRetriever) Init() error {
	options := &azidentity.ClientSecretCredentialOptions{AuthorityHost: c.authority}
	if credential, err := azidentity.NewClientSecretCredential(c.tenantId, c.clientId, c.clientSecret, options); err != nil {
		return err
	} else {
		c.credential = credential
		return nil
	}
}

func (c *clientSecretTokenRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) {
	accessToken, err := c.credential.GetToken(ctx, azcore.TokenRequestOptions{Scopes: scopes})
	if err != nil {
		return nil, err
	}

	return &AccessToken{Token: accessToken.Token, ExpiresOn: accessToken.ExpiresOn}, nil
}

func hashSecret(secret string) string {
	hash := sha256.New()
	_, _ = hash.Write([]byte(secret))
	return fmt.Sprintf("%x", hash.Sum(nil))
}
<|endoftext|>


<commit_before>// Copyright 2013 Google Inc. All Rights Reserved.
//
// 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 id3

import (
	"encoding/binary"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"unicode/utf16"
)

type ErrFormat struct {
	Format string
	Err    error
}

func (e ErrFormat) Error() string {
	return fmt.Sprintf("gotaglib: error parsing format %q: %v", e.Format, e.Err)
}

func parseBase128Int(bytes []byte) uint64 {
	var result uint64
	for _, b := range bytes {
		result = result << 7
		result |= uint64(b)
	}
	return result
}

func parseLeadingInt(s string) (int, error) {
	var intEnd int
	for intEnd < len(s) && '0' <= s[intEnd] && s[intEnd] <= '9' {
		intEnd++
	}
	return strconv.Atoi(s[0:intEnd])
}

func getTextIdentificationFrame(content []byte) ([]string, error) {
	normalized, err := parseText(content)
	if err != nil {
		return nil, err
	}
	return strings.Split(normalized, string([]byte{0})), nil
}

// Parses a string from frame data. The first byte represents the encoding:
//   0x01  ISO-8859-1
//   0x02  UTF-16 w/ BOM
//   0x03  UTF-16BE w/o BOM
//   0x04  UTF-8
//
// Refer to section 4 of http://id3.org/id3v2.4.0-structure
func parseText(strBytes []byte) (string, error) {
	if len(strBytes) == 0 {
		return "", errors.New("empty id3 frame")
	}
	if len(strBytes) < 2 {
		// Not an error according to the spec (because at least 1 byte big)
		return "", nil
	}
	encoding, strBytes := strBytes[0], strBytes[1:]

	switch encoding {
	case 0: // ISO-8859-1 text.
		return parseIso8859(strBytes), nil

	case 1: // UTF-16 with BOM.
		return parseUtf16WithBOM(strBytes)

	case 2: // UTF-16BE without BOM.
		return parseUtf16(strBytes, binary.BigEndian)

	case 3: // UTF-8 text.
		return parseUtf8(strBytes)

	default:
		return "", id3v24Err("invalid encoding byte %x", encoding)
	}
}

func parseIso8859(strBytes []byte) string {
	runes := make([]rune, len(strBytes))
	for i, b := range strBytes {
		runes[i] = rune(b)
	}
	return string(runes)
}

func parseUtf16WithBOM(strBytes []byte) (string, error) {
	if strBytes[0] == 0xFE && strBytes[1] == 0xFF {
		return parseUtf16(strBytes[2:], binary.BigEndian)
	}
	if strBytes[0] == 0xFF && strBytes[1] == 0xFE {
		return parseUtf16(strBytes[2:], binary.LittleEndian)
	}
	return "", id3v24Err("invalid byte order marker %x %x", strBytes[0], strBytes[1])
}

func parseUtf16(strBytes []byte, bo binary.ByteOrder) (string, error) {
	shorts := make([]uint16, 0, len(strBytes)/2)
	for i := 0; i < len(strBytes); i += 2 {
		short := bo.Uint16(strBytes[i : i+2])
		shorts = append(shorts, short)
	}

	return string(utf16.Decode(shorts)), nil
}

func parseUtf8(strBytes []byte) (string, error) {
	return string(strBytes), nil
}
<commit_msg>id3: Drop trailing NULs from frames.<commit_after>// Copyright 2013 Google Inc. All Rights Reserved.
//
// 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 id3

import (
	"encoding/binary"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"unicode/utf16"
)

type ErrFormat struct {
	Format string
	Err    error
}

func (e ErrFormat) Error() string {
	return fmt.Sprintf("gotaglib: error parsing format %q: %v", e.Format, e.Err)
}

func parseBase128Int(bytes []byte) uint64 {
	var result uint64
	for _, b := range bytes {
		result = result << 7
		result |= uint64(b)
	}
	return result
}

func parseLeadingInt(s string) (int, error) {
	var intEnd int
	for intEnd < len(s) && '0' <= s[intEnd] && s[intEnd] <= '9' {
		intEnd++
	}
	return strconv.Atoi(s[0:intEnd])
}

func getTextIdentificationFrame(content []byte) ([]string, error) {
	normalized, err := parseText(content)
	if err != nil {
		return nil, err
	}
	normalized = strings.TrimRight(normalized, string([]byte{0}))
	return strings.Split(normalized, string([]byte{0})), nil
}

// Parses a string from frame data. The first byte represents the encoding:
//   0x01  ISO-8859-1
//   0x02  UTF-16 w/ BOM
//   0x03  UTF-16BE w/o BOM
//   0x04  UTF-8
//
// Refer to section 4 of http://id3.org/id3v2.4.0-structure
func parseText(strBytes []byte) (string, error) {
	if len(strBytes) == 0 {
		return "", errors.New("empty id3 frame")
	}
	if len(strBytes) < 2 {
		// Not an error according to the spec (because at least 1 byte big)
		return "", nil
	}
	encoding, strBytes := strBytes[0], strBytes[1:]

	switch encoding {
	case 0: // ISO-8859-1 text.
		return parseIso8859(strBytes), nil

	case 1: // UTF-16 with BOM.
		return parseUtf16WithBOM(strBytes)

	case 2: // UTF-16BE without BOM.
		return parseUtf16(strBytes, binary.BigEndian)

	case 3: // UTF-8 text.
		return parseUtf8(strBytes)

	default:
		return "", id3v24Err("invalid encoding byte %x", encoding)
	}
}

func parseIso8859(strBytes []byte) string {
	runes := make([]rune, len(strBytes))
	for i, b := range strBytes {
		runes[i] = rune(b)
	}
	return string(runes)
}

func parseUtf16WithBOM(strBytes []byte) (string, error) {
	if strBytes[0] == 0xFE && strBytes[1] == 0xFF {
		return parseUtf16(strBytes[2:], binary.BigEndian)
	}
	if strBytes[0] == 0xFF && strBytes[1] == 0xFE {
		return parseUtf16(strBytes[2:], binary.LittleEndian)
	}
	return "", id3v24Err("invalid byte order marker %x %x", strBytes[0], strBytes[1])
}

func parseUtf16(strBytes []byte, bo binary.ByteOrder) (string, error) {
	shorts := make([]uint16, 0, len(strBytes)/2)
	for i := 0; i < len(strBytes); i += 2 {
		short := bo.Uint16(strBytes[i : i+2])
		shorts = append(shorts, short)
	}

	return string(utf16.Decode(shorts)), nil
}

func parseUtf8(strBytes []byte) (string, error) {
	return string(strBytes), nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The GoSNMPQuerier Authors. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package gosnmpquerier

import (
	"fmt"
	"log"
	"strconv"
)

type AsyncQuerier struct {
	Input      chan Query
	Output     chan Query
	Contention int
	snmpClient SnmpClient
}

func NewAsyncQuerier(contention int) *AsyncQuerier {
	querier := AsyncQuerier{
		Input:      make(chan Query, 10),
		Output:     make(chan Query, 10),
		Contention: contention,
		snmpClient: newSnmpClient(),
	}
	go querier.process()
	return &querier
}

type destinationProcessorInfo struct {
	input  chan Query
	output chan Query
	done   chan bool
}

func (querier *AsyncQuerier) process() {
	log.Println("AsyncQuerier process begin")
	m := make(map[string]destinationProcessorInfo)

	for query := range querier.Input {
		if _, exists := m[query.Destination]; exists == false {
			processorInfo := createProcessorInfo(querier.Output)
			m[query.Destination] = processorInfo
			createProcessors(processorInfo, querier, query.Destination)
		}
		m[query.Destination].input <- query
	}
	log.Println("AsyncQuerier process terminating")

	waitUntilProcessorEnd(m, querier.Contention)
	log.Println("closing output")
	close(querier.Output)
}
func createProcessorInfo(output chan Query) destinationProcessorInfo {
	return destinationProcessorInfo{
		input:  make(chan Query, 10),
		output: output,
		done:   make(chan bool, 1),
	}
}

func createProcessors(processorInfo destinationProcessorInfo, querier *AsyncQuerier, destination string) {
	for i := 0; i < querier.Contention; i++ {
		go processQueriesFromChannel(
			querier,
			processorInfo.input,
			processorInfo.output,
			processorInfo.done,
			string(destination)+string("_")+strconv.Itoa(i))
	}
}

func waitUntilProcessorEnd(m map[string]destinationProcessorInfo, contention int) {
	for destination, processorInfo := range m {
		log.Println("closing:", processorInfo.input)
		close(processorInfo.input)
		for i := 0; i < contention; i++ {
			<-processorInfo.done
		}
		delete(m, destination)
	}
}

func (querier *AsyncQuerier) handleQuery(query *Query) {
	switch query.Cmd {
	case WALK:
		if len(query.Oids) == 1 {
			query.Response, query.Error = querier.snmpClient.walk(query.Destination, query.Community, query.Oids[0], query.Timeout, query.Retries)
		} else {
			query.Error = fmt.Errorf("multi Oid Walk not supported")
		}
	case GET:
		query.Response, query.Error = querier.snmpClient.get(query.Destination, query.Community, query.Oids, query.Timeout, query.Retries)
	case GETNEXT:
		query.Response, query.Error = querier.snmpClient.getnext(query.Destination, query.Community, query.Oids, query.Timeout, query.Retries)
	}
}

func processQueriesFromChannel(querier *AsyncQuerier, input chan Query, processed chan Query, done chan bool, processorId string) {
	for query := range input {
		querier.handleQuery(&query)
		processed <- query
	}
	done <- true
	log.Println(processorId, "terminated")
}
<commit_msg>Refactor<commit_after>// Copyright 2014 The GoSNMPQuerier Authors. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package gosnmpquerier

import (
	"fmt"
	"log"
	"strconv"
)

type AsyncQuerier struct {
	Input      chan Query
	Output     chan Query
	Contention int
	snmpClient SnmpClient
}

func NewAsyncQuerier(contention int) *AsyncQuerier {
	querier := AsyncQuerier{
		Input:      make(chan Query, 10),
		Output:     make(chan Query, 10),
		Contention: contention,
		snmpClient: newSnmpClient(),
	}
	go querier.process()
	return &querier
}

type destinationProcessor struct {
	input  chan Query
	output chan Query
	done   chan bool
}

func (querier *AsyncQuerier) process() {
	log.Println("AsyncQuerier process begin")
	m := make(map[string]destinationProcessor)

	for query := range querier.Input {
		if _, exists := m[query.Destination]; exists == false {
			processorInfo := createProcessorInfo(querier.Output)
			m[query.Destination] = processorInfo
			createProcessors(processorInfo, querier, query.Destination)
		}
		m[query.Destination].input <- query
	}
	log.Println("AsyncQuerier process terminating")

	waitUntilProcessorEnd(m, querier.Contention)
	log.Println("closing output")
	close(querier.Output)
}
func createProcessorInfo(output chan Query) destinationProcessor {
	return destinationProcessor{
		input:  make(chan Query, 10),
		output: output,
		done:   make(chan bool, 1),
	}
}

func createProcessors(processorInfo destinationProcessor, querier *AsyncQuerier, destination string) {
	for i := 0; i < querier.Contention; i++ {
		go processorInfo.processQueriesFromChannel(
			querier,
			string(destination)+string("_")+strconv.Itoa(i))
	}
}

func waitUntilProcessorEnd(m map[string]destinationProcessor, contention int) {
	for destination, processorInfo := range m {
		log.Println("closing:", processorInfo.input)
		close(processorInfo.input)
		for i := 0; i < contention; i++ {
			<-processorInfo.done
		}
		delete(m, destination)
	}
}

func (querier *AsyncQuerier) handleQuery(query *Query) {
	switch query.Cmd {
	case WALK:
		if len(query.Oids) == 1 {
			query.Response, query.Error = querier.snmpClient.walk(query.Destination, query.Community, query.Oids[0], query.Timeout, query.Retries)
		} else {
			query.Error = fmt.Errorf("multi Oid Walk not supported")
		}
	case GET:
		query.Response, query.Error = querier.snmpClient.get(query.Destination, query.Community, query.Oids, query.Timeout, query.Retries)
	case GETNEXT:
		query.Response, query.Error = querier.snmpClient.getnext(query.Destination, query.Community, query.Oids, query.Timeout, query.Retries)
	}
}

func (processor * destinationProcessor) processQueriesFromChannel(querier *AsyncQuerier, processorId string) {
	for query := range processor.input {
		querier.handleQuery(&query)
		processor.output <- query
	}
	processor.done <- true
	log.Println(processorId, "terminated")
}
<|endoftext|>


<commit_before>package ast_test

import (
	"strings"
	"testing"

	"github.com/DeedleFake/wdte/ast"
)

func printTree(t *testing.T, cur ast.Node, depth int) {
	indent := strings.Repeat("  ", depth)
	switch cur := cur.(type) {
	case *ast.Term:
		t.Logf("%v%v", indent, cur)

	case *ast.NTerm:
		t.Logf("%v(%v", indent, cur)
		for _, c := range cur.Children() {
			printTree(t, c, depth+1)
		}
		t.Logf("%v)", indent)

	case *ast.Epsilon:
		t.Logf("%vε", indent)

	default:
		t.Fatalf("Unexpected node: %#v", cur)
	}
}

func TestParse(t *testing.T) {
	root, err := ast.Parse(strings.NewReader(`"test" => t; + x y => nil;`))
	if err != nil {
		t.Fatal(err)
	}
	printTree(t, root, 0)
}
<commit_msg>ast: Add Fibonacci test.<commit_after>package ast_test

import (
	"strings"
	"testing"

	"github.com/DeedleFake/wdte/ast"
)

func printTree(t *testing.T, cur ast.Node, depth int) {
	indent := strings.Repeat("  ", depth)
	switch cur := cur.(type) {
	case *ast.Term:
		t.Logf("%v%v", indent, cur)

	case *ast.NTerm:
		t.Logf("%v(%v", indent, cur)
		for _, c := range cur.Children() {
			printTree(t, c, depth+1)
		}
		t.Logf("%v)", indent)

	case *ast.Epsilon:
		t.Logf("%vε", indent)

	default:
		t.Fatalf("Unexpected node: %#v", cur)
	}
}

func TestParse(t *testing.T) {
	//const test = `"test" => t; + x y => nil;`

	const test = `
'test' => test;

fib n => switch n {
	0 => 0;
	default => + (fib (- n 1)) (fib (- n 2));
};

main => print (fib 5);
`

	root, err := ast.Parse(strings.NewReader(test))
	if err != nil {
		t.Fatal(err)
	}
	printTree(t, root, 0)
}
<|endoftext|>


<commit_before>package ast_test

import (
	"strings"
	"testing"

	"github.com/DeedleFake/wdte/ast"
)

func printTree(t *testing.T, cur ast.Node, depth int) {
	indent := strings.Repeat("  ", depth)
	switch cur := cur.(type) {
	case *ast.Term:
		t.Logf("%v%v", indent, cur)

	case *ast.NTerm:
		t.Logf("%v(%v", indent, cur)
		for _, c := range cur.Children() {
			printTree(t, c, depth+1)
		}
		t.Logf("%v)", indent)

	case *ast.Epsilon:
		t.Logf("%vε", indent)

	default:
		t.Fatalf("Unexpected node: %#v", cur)
	}
}

func TestParse(t *testing.T) {
	//const test = `"test" => t; + x y => nil;`

	const test = `
'test' => test;

fib n => switch n {
	0 => 0;
	default => + (fib (- n 1;);) (fib (- n 2;););
};

main => print (fib 5;);
`

	root, err := ast.Parse(strings.NewReader(test))
	if err != nil {
		t.Fatal(err)
	}
	printTree(t, root, 0)
}
<commit_msg>ast: Remove optional semicolons from test.<commit_after>package ast_test

import (
	"strings"
	"testing"

	"github.com/DeedleFake/wdte/ast"
)

func printTree(t *testing.T, cur ast.Node, depth int) {
	indent := strings.Repeat("  ", depth)
	switch cur := cur.(type) {
	case *ast.Term:
		t.Logf("%v%v", indent, cur)

	case *ast.NTerm:
		t.Logf("%v(%v", indent, cur)
		for _, c := range cur.Children() {
			printTree(t, c, depth+1)
		}
		t.Logf("%v)", indent)

	case *ast.Epsilon:
		t.Logf("%vε", indent)

	default:
		t.Fatalf("Unexpected node: %#v", cur)
	}
}

func TestParse(t *testing.T) {
	//const test = `"test" => t; + x y => nil;`

	const test = `
'test' => test;

fib n => switch n {
	0 => 0;
	default => + (fib (- n 1)) (fib (- n 2));
};

main => print (fib 5);
`

	root, err := ast.Parse(strings.NewReader(test))
	if err != nil {
		t.Fatal(err)
	}
	printTree(t, root, 0)
}
<|endoftext|>


<commit_before>// Copyright Istio Authors
//
// 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 xds

import (
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	configaggregate "istio.io/istio/pilot/pkg/config/aggregate"
	"istio.io/istio/pilot/pkg/config/memory"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/serviceregistry"
	"istio.io/istio/pilot/pkg/serviceregistry/aggregate"
	controllermemory "istio.io/istio/pilot/pkg/serviceregistry/memory"
	"istio.io/istio/pilot/pkg/serviceregistry/serviceentry"
	"istio.io/istio/pkg/config/mesh"
	"istio.io/istio/pkg/config/schema/collections"
)

// Server represents the XDS serving feature of Istiod (pilot).
// Unlike bootstrap/, this packet has no dependencies on K8S, CA,
// and other features. It'll be used initially in the istio-agent,
// to provide a minimal proxy while reusing the same code as istiod.
// Portions of the code will also be used in istiod - after it becomes
// stable the plan is to refactor bootstrap to use this code instead
// of directly bootstrapping XDS.
//
// The server support proxy/federation of multiple sources - last part
// or parity with MCP/Galley and MCP-over-XDS.
type SimpleServer struct {
	// DiscoveryServer is the gRPC XDS implementation
	// Env and MemRegistry are available as fields, as well as the default
	// PushContext.
	DiscoveryServer *DiscoveryServer

	// MemoryStore is an in-memory config store, part of the aggregate store
	// used by the discovery server.
	MemoryConfigStore model.IstioConfigStore

	// GRPCListener is the listener used for GRPC. For agent it is
	// an insecure port, bound to 127.0.0.1
	GRPCListener net.Listener

	// syncCh is used for detecting if the stores have synced,
	// which needs to happen before serving requests.
	syncCh chan string

	ConfigStoreCache model.ConfigStoreCache
}

// Creates an basic, functional discovery server, using the same code as Istiod, but
// backed by an in-memory config and endpoint stores.
//
// Can be used in tests, or as a minimal XDS discovery server with no dependency on K8S or
// the complex bootstrap used by Istiod. A memory registry and memory config store are used to
// generate the configs - they can be programmatically updated.
func NewXDS(stop chan struct{}) *SimpleServer {
	// Prepare a working XDS server, with aggregate config and registry stores and a memory store for each.
	// TODO: refactor bootstrap code to use this server, and add more registries.

	env := &model.Environment{
		PushContext: model.NewPushContext(),
	}
	mc := mesh.DefaultMeshConfig()
	env.Watcher = mesh.NewFixedWatcher(&mc)
	env.PushContext.Mesh = env.Watcher.Mesh()
	env.Init()

	ds := NewDiscoveryServer(env, nil, "istiod", "istio-system")
	ds.InitGenerators(env, "istio-system")
	ds.CachesSynced()

	// Config will have a fixed format:
	// - aggregate store
	// - one primary (local) memory config
	// Additional stores can be added dynamically - for example by push or reference from a server.
	// This is used to implement and test XDS federation (which is not yet final).

	// In-memory config store, controller and istioConfigStore
	schemas := collections.Pilot

	store := memory.Make(schemas)
	s := &SimpleServer{
		DiscoveryServer: ds,
	}
	s.syncCh = make(chan string, len(schemas.All()))
	configController := memory.NewController(store)
	s.MemoryConfigStore = model.MakeIstioStore(configController)

	// Endpoints/Clusters - using the config store for ServiceEntries
	serviceControllers := aggregate.NewController(aggregate.Options{})

	serviceEntryStore := serviceentry.NewServiceDiscovery(configController, s.MemoryConfigStore, ds)
	serviceEntryRegistry := serviceregistry.Simple{
		ProviderID:       "External",
		Controller:       serviceEntryStore,
		ServiceDiscovery: serviceEntryStore,
	}
	serviceControllers.AddRegistry(serviceEntryRegistry)

	sd := controllermemory.NewServiceDiscovery(nil)
	sd.EDSUpdater = ds
	ds.MemRegistry = sd
	serviceControllers.AddRegistry(serviceregistry.Simple{
		ProviderID:       "Mem",
		ServiceDiscovery: sd,
		Controller:       sd.Controller,
	})
	env.ServiceDiscovery = serviceControllers

	go configController.Run(stop)

	// configStoreCache - with HasSync interface
	aggregateConfigController, err := configaggregate.MakeCache([]model.ConfigStoreCache{
		configController,
	})
	if err != nil {
		log.Fatala("Creating aggregate config ", err)
	}

	// TODO: fix the mess of store interfaces - most are too generic for their own good.
	s.ConfigStoreCache = aggregateConfigController
	env.IstioConfigStore = model.MakeIstioStore(aggregateConfigController)

	return s
}

func (s *SimpleServer) StartGRPC(addr string) error {
	lis, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	gs := grpc.NewServer()
	s.DiscoveryServer.Register(gs)
	reflection.Register(gs)
	s.GRPCListener = lis
	go func() {
		err = gs.Serve(lis)
		if err != nil {
			log.Info("Serve done ", err)
		}
	}()
	return nil
}
<commit_msg>Clean up for simple server (#35105)<commit_after>// Copyright Istio Authors
//
// 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 xds

import (
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	configaggregate "istio.io/istio/pilot/pkg/config/aggregate"
	"istio.io/istio/pilot/pkg/config/memory"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/serviceregistry"
	"istio.io/istio/pilot/pkg/serviceregistry/aggregate"
	controllermemory "istio.io/istio/pilot/pkg/serviceregistry/memory"
	"istio.io/istio/pilot/pkg/serviceregistry/serviceentry"
	"istio.io/istio/pkg/config/mesh"
	"istio.io/istio/pkg/config/schema/collections"
)

// Server represents the XDS serving feature of Istiod (pilot).
// Unlike bootstrap/, this packet has no dependencies on K8S, CA,
// and other features. It'll be used initially in the istio-agent,
// to provide a minimal proxy while reusing the same code as istiod.
// Portions of the code will also be used in istiod - after it becomes
// stable the plan is to refactor bootstrap to use this code instead
// of directly bootstrapping XDS.
//
// The server support proxy/federation of multiple sources - last part
// or parity with MCP/Galley and MCP-over-XDS.
type SimpleServer struct {
	// DiscoveryServer is the gRPC XDS implementation
	// Env and MemRegistry are available as fields, as well as the default
	// PushContext.
	DiscoveryServer *DiscoveryServer

	// MemoryStore is an in-memory config store, part of the aggregate store
	// used by the discovery server.
	MemoryConfigStore model.IstioConfigStore

	// GRPCListener is the listener used for GRPC. For agent it is
	// an insecure port, bound to 127.0.0.1
	GRPCListener net.Listener

	// syncCh is used for detecting if the stores have synced,
	// which needs to happen before serving requests.
	syncCh chan string

	ConfigStoreCache model.ConfigStoreCache
}

// Creates an basic, functional discovery server, using the same code as Istiod, but
// backed by an in-memory config and endpoint stores.
//
// Can be used in tests, or as a minimal XDS discovery server with no dependency on K8S or
// the complex bootstrap used by Istiod. A memory registry and memory config store are used to
// generate the configs - they can be programmatically updated.
func NewXDS(stop chan struct{}) *SimpleServer {
	// Prepare a working XDS server, with aggregate config and registry stores and a memory store for each.
	// TODO: refactor bootstrap code to use this server, and add more registries.

	env := &model.Environment{
		PushContext: model.NewPushContext(),
	}
	mc := mesh.DefaultMeshConfig()
	env.Watcher = mesh.NewFixedWatcher(&mc)
	env.PushContext.Mesh = env.Watcher.Mesh()
	env.Init()

	ds := NewDiscoveryServer(env, nil, "istiod", "istio-system")
	ds.InitGenerators(env, "istio-system")
	ds.CachesSynced()

	// Config will have a fixed format:
	// - aggregate store
	// - one primary (local) memory config
	// Additional stores can be added dynamically - for example by push or reference from a server.
	// This is used to implement and test XDS federation (which is not yet final).

	// In-memory config store, controller and istioConfigStore
	schemas := collections.Pilot

	store := memory.Make(schemas)
	s := &SimpleServer{
		DiscoveryServer: ds,
	}
	s.syncCh = make(chan string, len(schemas.All()))
	configController := memory.NewController(store)
	s.MemoryConfigStore = model.MakeIstioStore(configController)

	// Endpoints/Clusters - using the config store for ServiceEntries
	serviceControllers := aggregate.NewController(aggregate.Options{})

	serviceEntryStore := serviceentry.NewServiceDiscovery(configController, s.MemoryConfigStore, ds)
	serviceControllers.AddRegistry(serviceEntryStore)

	sd := controllermemory.NewServiceDiscovery(nil)
	sd.EDSUpdater = ds
	ds.MemRegistry = sd
	serviceControllers.AddRegistry(serviceregistry.Simple{
		ProviderID:       "Mem",
		ServiceDiscovery: sd,
		Controller:       sd.Controller,
	})
	env.ServiceDiscovery = serviceControllers

	go configController.Run(stop)

	// configStoreCache - with HasSync interface
	aggregateConfigController, err := configaggregate.MakeCache([]model.ConfigStoreCache{
		configController,
	})
	if err != nil {
		log.Fatala("Creating aggregate config ", err)
	}

	// TODO: fix the mess of store interfaces - most are too generic for their own good.
	s.ConfigStoreCache = aggregateConfigController
	env.IstioConfigStore = model.MakeIstioStore(aggregateConfigController)

	return s
}

func (s *SimpleServer) StartGRPC(addr string) error {
	lis, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	gs := grpc.NewServer()
	s.DiscoveryServer.Register(gs)
	reflection.Register(gs)
	s.GRPCListener = lis
	go func() {
		err = gs.Serve(lis)
		if err != nil {
			log.Info("Serve done ", err)
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>// Package build implements Pipe and can build Go projects for
// several platforms, with pre and post hook support.
package build

import (
	"errors"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/goreleaser/goreleaser/context"
	"golang.org/x/sync/errgroup"
)

// Pipe for build
type Pipe struct{}

// Description of the pipe
func (Pipe) Description() string {
	return "Building binaries"
}

// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
	if err := runHook(ctx.Config.Build.Hooks.Pre); err != nil {
		return err
	}
	sem := make(chan bool, 4)
	var g errgroup.Group
	for _, goos := range ctx.Config.Build.Goos {
		for _, goarch := range ctx.Config.Build.Goarch {
			sem <- true
			goos := goos
			goarch := goarch
			if !valid(goos, goarch) {
				<-sem
				continue
			}
			name, err := nameFor(ctx, goos, goarch)
			if err != nil {
				return err
			}
			ctx.Archives[goos+goarch] = name
			g.Go(func() error {
				defer func() {
					<-sem
				}()
				return build(name, goos, goarch, ctx)
			})
		}
	}
	if err := g.Wait(); err != nil {
		return err
	}
	return runHook(ctx.Config.Build.Hooks.Post)
}

func runHook(hook string) error {
	if hook == "" {
		return nil
	}
	log.Println("Running hook", hook)
	cmd := strings.Fields(hook)
	return run(runtime.GOOS, runtime.GOARCH, cmd)
}

func build(name, goos, goarch string, ctx *context.Context) error {
	output := filepath.Join(
		ctx.Config.Dist,
		name,
		ctx.Config.Build.Binary+extFor(goos),
	)
	log.Println("Building", output)
	cmd := []string{"go", "build"}
	if ctx.Config.Build.Flags != "" {
		cmd = append(cmd, strings.Fields(ctx.Config.Build.Flags)...)
	}
	flags, err := ldflags(ctx)
	if err != nil {
		return err
	}
	cmd = append(cmd, "-ldflags="+flags, "-o", output, ctx.Config.Build.Main)
	return run(goos, goarch, cmd)
}

func run(goos, goarch string, command []string) error {
	cmd := exec.Command(command[0], command[1:]...)
	cmd.Env = append(cmd.Env, os.Environ()...)
	cmd.Env = append(cmd.Env, "GOOS="+goos, "GOARCH="+goarch)
	if out, err := cmd.CombinedOutput(); err != nil {
		return errors.New(string(out))
	}
	return nil
}
<commit_msg>added log<commit_after>// Package build implements Pipe and can build Go projects for
// several platforms, with pre and post hook support.
package build

import (
	"errors"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/goreleaser/goreleaser/context"
	"golang.org/x/sync/errgroup"
)

// Pipe for build
type Pipe struct{}

// Description of the pipe
func (Pipe) Description() string {
	return "Building binaries"
}

// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
	if err := runHook(ctx.Config.Build.Hooks.Pre); err != nil {
		return err
	}
	sem := make(chan bool, 4)
	var g errgroup.Group
	for _, goos := range ctx.Config.Build.Goos {
		for _, goarch := range ctx.Config.Build.Goarch {
			sem <- true
			goos := goos
			goarch := goarch
			if !valid(goos, goarch) {
				log.Printf("Skipped build for %v/%v\n", goos, goarch)
				<-sem
				continue
			}
			name, err := nameFor(ctx, goos, goarch)
			if err != nil {
				return err
			}
			ctx.Archives[goos+goarch] = name
			g.Go(func() error {
				defer func() {
					<-sem
				}()
				return build(name, goos, goarch, ctx)
			})
		}
	}
	if err := g.Wait(); err != nil {
		return err
	}
	return runHook(ctx.Config.Build.Hooks.Post)
}

func runHook(hook string) error {
	if hook == "" {
		return nil
	}
	log.Println("Running hook", hook)
	cmd := strings.Fields(hook)
	return run(runtime.GOOS, runtime.GOARCH, cmd)
}

func build(name, goos, goarch string, ctx *context.Context) error {
	output := filepath.Join(
		ctx.Config.Dist,
		name,
		ctx.Config.Build.Binary+extFor(goos),
	)
	log.Println("Building", output)
	cmd := []string{"go", "build"}
	if ctx.Config.Build.Flags != "" {
		cmd = append(cmd, strings.Fields(ctx.Config.Build.Flags)...)
	}
	flags, err := ldflags(ctx)
	if err != nil {
		return err
	}
	cmd = append(cmd, "-ldflags="+flags, "-o", output, ctx.Config.Build.Main)
	return run(goos, goarch, cmd)
}

func run(goos, goarch string, command []string) error {
	cmd := exec.Command(command[0], command[1:]...)
	cmd.Env = append(cmd.Env, os.Environ()...)
	cmd.Env = append(cmd.Env, "GOOS="+goos, "GOARCH="+goarch)
	if out, err := cmd.CombinedOutput(); err != nil {
		return errors.New(string(out))
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"
	"time"
)

type updateJob struct {
	progress   *Progress
	onProgress chan *Progress
}

func (u *updateJob) start() {

	u.progress = &Progress{
		Running:   true,
		startTime: time.Now(),
	}

	u.updateProgress(0, "Looking for updates", "")

	u.cleanup()

	err := u.setReadWrite(true)
	if err != nil {
		u.updateProgress(0, "Failed to enable disk writing", fmt.Sprintf("Error: %s", err))
		return
	}
	defer u.setReadWrite(false)

	log.Infof("Updating from repositories")

	err = u.updateCache(45, 0, 25)
	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	u.updateProgress(27, "Processing available updates", "")

	updates, err := u.getAvailableUpdates()

	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	updates = append(updates, AvailableUpdate{
		Name: "ninjasphere", // Always force it
	})

	// Check to see if our "get out of jail free" card has been played
	for _, update := range updates {
		if update.Name == "sphere-idspispopd" {
			err = u.installUpdates([]AvailableUpdate{update})

			if err != nil {
				u.updateProgress(0, "Failed running pre-install script", fmt.Sprintf("Error: %s", err))
				return
			}

			updates, err = u.getAvailableUpdates()

			if err != nil {
				u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
				return
			}
		}
	}

	u.autoRemove()

	log.Infof("%d packages to update: %v", len(updates), updates)

	if len(updates) > 0 {

		u.updateProgress(30, "Installing updates", "")

		err = u.installUpdates(updates)

		if err != nil {
			u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
			return
		}
	}

	u.updateProgress(100, "Finished", "")
}

func (u *updateJob) updateProgress(percent float64, description, err string) {

	if percent == 100 || err != "" {
		u.progress.Running = false
	}

	if percent > u.progress.Percent {
		u.progress.Percent = percent
	}

	if err != "" {
		u.progress.Error = &err
	}

	if description != "" {
		u.progress.Description = description
	}

	u.onProgress <- u.progress
}

func (u *updateJob) setReadWrite(writing bool) error {
	if runtime.GOOS != "linux" {
		return nil
	}

	mode := "ro"
	if writing {
		mode = "rw"
	}

	cmd := exec.Command("mount", "-o", "remount,"+mode, "/")

	output, err := cmd.Output()
	log.Infof("Output from mount: %s", output)

	return err
}

func (u *updateJob) updateCache(expectedLines float64, startPercent float64, totalPercent float64) error {

	if runtime.GOOS != "linux" {
		return nil
	}

	updateLines := 0.0

	cmd := exec.Command("apt-get", "update", "-q")

	reader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	for {
		_, _, err := bufReader.ReadLine()

		if err != nil {
			//log.Infof("ERR:%s", err)
			break
		}

		updateLines++
		//cleaned := invalidChar.ReplaceAll([]byte(x[0:n]), []byte(""))

		u.updateProgress(startPercent+math.Min(totalPercent, (updateLines/expectedLines)*totalPercent), "", "")
		//	log.Infof("GOT: |%s| %t", line, isPrefix)
	}

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("updateCache Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to update cache. Code: %d", status.ExitStatus())
			}
		} else {
			log.Infof("Update cache : cmd.Wait: %v", err)
		}
	}

	return nil
}

func (u *updateJob) cleanup() {
	cmd := exec.Command("dpkg", "--configure", "-a")

	output, _ := cmd.Output()

	log.Infof("Output from dpkg: %s", output)

}

func (u *updateJob) autoRemove() {
	cmd := exec.Command("apt-get", "auto-remove")

	output, _ := cmd.Output()

	log.Infof("Output from apt-get autoremove: %s", output)
}

func (u *updateJob) getAvailableUpdates() ([]AvailableUpdate, error) {
	var err error
	var available []byte

	ioutil.WriteFile("./available-updates.sh", []byte(`#!/bin/bash
	  apt-get -s dist-upgrade| awk -F'[][() ]+' '/^Inst/{printf "%s\t%s\t%s\n", $2,$3,$4}'`), os.FileMode(755))

	cmd := exec.Command("./available-updates.sh")

	if runtime.GOOS == "linux" {
		available, err = cmd.Output()
	} else {
		available, err = ioutil.ReadFile("./updates.txt")
	}

	if err != nil {
		return nil, fmt.Errorf("Failed to get updatable packages. Error: %s", err)
	}

	var updates []AvailableUpdate

	for _, line := range strings.Split(string(available), "\n") {
		s := strings.Split(line, "\t")
		if len(s) == 3 && strings.Contains(line, "spheramid") && !strings.Contains(line, "sphere-updates") && !strings.Contains(line, "sphere-setup-assistant") {
			updates = append(updates, AvailableUpdate{s[0], s[1], s[2]})
		}
	}

	if runtime.GOOS == "linux" {
		if err := cmd.Wait(); err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// The program has exited with an exit code != 0
				// There is no plattform independent way to retrieve
				// the exit code, but the following will work on Unix
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					log.Infof("Bad Exit Status: %d", status.ExitStatus())
					return nil, fmt.Errorf("Failed to get updatable packages. Code: %d", status.ExitStatus())
				}
			} else {
				log.Infof("Get updatable : cmd.Wait: %v", err)
			}
		}
	}

	return updates, nil
}

func (u *updateJob) installUpdates(updates []AvailableUpdate) error {

	var cmd *exec.Cmd
	if runtime.GOOS == "linux" {
		args := []string{"install", "-yy", "-q"}
		for _, update := range updates {
			args = append(args, update.Name)
		}

		log.Infof("Running update command : apt-get %s", strings.Join(args, " "))

		cmd = exec.Command("apt-get", args...)
		cmd.Stderr = os.Stderr
	} else {
		cmd = exec.Command("cat", "./upgrade.txt")
	}

	os.Setenv("DEBIAN_FRONTEND", "noninteractive")

	reader, err := cmd.StdoutPipe()

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	pointsPerPackage := float64(10) / float64(len(updates))

	percent := 30.0

	go func() {
		for {
			line, _, err := bufReader.ReadLine()

			log.Infof("apt: " + string(line))

			if err != nil {
				//log.Infof("ERR:%s", err)
				break
			}

			if strings.HasPrefix(string(line), "Reading package lists") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Building dependency tree") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Reading state information") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Need to get") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Get:") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Unpacking ") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Setting up ") {
				percent = percent + pointsPerPackage
			}

			u.updateProgress(math.Min(99, percent), "Installing updates", "")

		}
	}()

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("installUpdates Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to install updates. Code:%d", status.ExitStatus())
			}
		} else {
			log.Infof("cmd.Wait: %v", err)
		}
	}

	return nil
}
<commit_msg>Recalculate pointsPerPackage when apt tells us what it's going to be doing.<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type updateJob struct {
	progress   *Progress
	onProgress chan *Progress
}

func (u *updateJob) start() {

	u.progress = &Progress{
		Running:   true,
		startTime: time.Now(),
	}

	u.updateProgress(0, "Looking for updates", "")

	u.cleanup()

	err := u.setReadWrite(true)
	if err != nil {
		u.updateProgress(0, "Failed to enable disk writing", fmt.Sprintf("Error: %s", err))
		return
	}
	defer u.setReadWrite(false)

	log.Infof("Updating from repositories")

	err = u.updateCache(45, 0, 25)
	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	u.updateProgress(27, "Processing available updates", "")

	updates, err := u.getAvailableUpdates()

	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	updates = append(updates, AvailableUpdate{
		Name: "ninjasphere", // Always force it
	})

	// Check to see if our "get out of jail free" card has been played
	for _, update := range updates {
		if update.Name == "sphere-idspispopd" {
			err = u.installUpdates([]AvailableUpdate{update})

			if err != nil {
				u.updateProgress(0, "Failed running pre-install script", fmt.Sprintf("Error: %s", err))
				return
			}

			updates, err = u.getAvailableUpdates()

			if err != nil {
				u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
				return
			}
		}
	}

	u.autoRemove()

	log.Infof("%d packages to update: %v", len(updates), updates)

	if len(updates) > 0 {

		u.updateProgress(30, "Installing updates", "")

		err = u.installUpdates(updates)

		if err != nil {
			u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
			return
		}
	}

	u.updateProgress(100, "Finished", "")
}

func (u *updateJob) updateProgress(percent float64, description, err string) {

	if percent == 100 || err != "" {
		u.progress.Running = false
	}

	if percent > u.progress.Percent {
		u.progress.Percent = percent
	}

	if err != "" {
		u.progress.Error = &err
	}

	if description != "" {
		u.progress.Description = description
	}

	u.onProgress <- u.progress
}

func (u *updateJob) setReadWrite(writing bool) error {
	if runtime.GOOS != "linux" {
		return nil
	}

	mode := "ro"
	if writing {
		mode = "rw"
	}

	cmd := exec.Command("mount", "-o", "remount,"+mode, "/")

	output, err := cmd.Output()
	log.Infof("Output from mount: %s", output)

	return err
}

func (u *updateJob) updateCache(expectedLines float64, startPercent float64, totalPercent float64) error {

	if runtime.GOOS != "linux" {
		return nil
	}

	updateLines := 0.0

	cmd := exec.Command("apt-get", "update", "-q")

	reader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	for {
		_, _, err := bufReader.ReadLine()

		if err != nil {
			//log.Infof("ERR:%s", err)
			break
		}

		updateLines++
		//cleaned := invalidChar.ReplaceAll([]byte(x[0:n]), []byte(""))

		u.updateProgress(startPercent+math.Min(totalPercent, (updateLines/expectedLines)*totalPercent), "", "")
		//	log.Infof("GOT: |%s| %t", line, isPrefix)
	}

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("updateCache Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to update cache. Code: %d", status.ExitStatus())
			}
		} else {
			log.Infof("Update cache : cmd.Wait: %v", err)
		}
	}

	return nil
}

func (u *updateJob) cleanup() {
	cmd := exec.Command("dpkg", "--configure", "-a")

	output, _ := cmd.Output()

	log.Infof("Output from dpkg: %s", output)

}

func (u *updateJob) autoRemove() {
	cmd := exec.Command("apt-get", "auto-remove")

	output, _ := cmd.Output()

	log.Infof("Output from apt-get autoremove: %s", output)
}

func (u *updateJob) getAvailableUpdates() ([]AvailableUpdate, error) {
	var err error
	var available []byte

	ioutil.WriteFile("./available-updates.sh", []byte(`#!/bin/bash
	  apt-get -s dist-upgrade| awk -F'[][() ]+' '/^Inst/{printf "%s\t%s\t%s\n", $2,$3,$4}'`), os.FileMode(755))

	cmd := exec.Command("./available-updates.sh")

	if runtime.GOOS == "linux" {
		available, err = cmd.Output()
	} else {
		available, err = ioutil.ReadFile("./updates.txt")
	}

	if err != nil {
		return nil, fmt.Errorf("Failed to get updatable packages. Error: %s", err)
	}

	var updates []AvailableUpdate

	for _, line := range strings.Split(string(available), "\n") {
		s := strings.Split(line, "\t")
		if len(s) == 3 && strings.Contains(line, "spheramid") && !strings.Contains(line, "sphere-updates") && !strings.Contains(line, "sphere-setup-assistant") {
			updates = append(updates, AvailableUpdate{s[0], s[1], s[2]})
		}
	}

	if runtime.GOOS == "linux" {
		if err := cmd.Wait(); err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// The program has exited with an exit code != 0
				// There is no plattform independent way to retrieve
				// the exit code, but the following will work on Unix
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					log.Infof("Bad Exit Status: %d", status.ExitStatus())
					return nil, fmt.Errorf("Failed to get updatable packages. Code: %d", status.ExitStatus())
				}
			} else {
				log.Infof("Get updatable : cmd.Wait: %v", err)
			}
		}
	}

	return updates, nil
}

var numberToInstallRegex = regexp.MustCompile(`(\d+) upgraded, (\d+) newly installed, (\d+) to remove`)

func (u *updateJob) installUpdates(updates []AvailableUpdate) error {

	var cmd *exec.Cmd
	if runtime.GOOS == "linux" {

		os.Setenv("DEBIAN_FRONTEND", "noninteractive")
		args := []string{"install", "-yy", "-q"}
		for _, update := range updates {
			args = append(args, update.Name)
		}

		log.Infof("Running update command : apt-get %s", strings.Join(args, " "))

		cmd = exec.Command("apt-get", args...)
		cmd.Stderr = os.Stderr
	} else {
		cmd = exec.Command("cat", "./upgrade.txt")
	}

	reader, err := cmd.StdoutPipe()

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	pointsPerPackage := float64(10) / float64(len(updates))

	percent := 30.0

	go func() {
		for {
			line, _, err := bufReader.ReadLine()

			log.Infof("apt: " + string(line))

			if err != nil {
				//log.Infof("ERR:%s", err)
				break
			}

			numPackages := numberToInstallRegex.FindStringSubmatch(string(line))

			if numPackages != nil {
				p := 0.0
				for _, n := range numPackages[1:] {
					i, err := strconv.ParseInt(n, 16, 10)
					if err != nil {
						log.Warningf("Failed to parse number of packages: %s", n)
					} else {
						p += float64(i)
					}
				}

				pointsPerPackage = float64(10) / p

				log.Debugf("Found nuber of packages: %f, points per package: %f", p, pointsPerPackage)
			}

			if strings.HasPrefix(string(line), "Reading package lists") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Building dependency tree") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Reading state information") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Need to get") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Get:") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Unpacking ") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Setting up ") {
				percent = percent + pointsPerPackage
			}

			u.updateProgress(math.Min(99, percent), "Installing updates", "")
		}
	}()

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("installUpdates Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to install updates. Code:%d", status.ExitStatus())
			}
		} else {
			log.Infof("cmd.Wait: %v", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 uSwitch
//
// 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 metadata

import (
	log "github.com/sirupsen/logrus"
	"net/http"
)

type statusWriter struct {
	http.ResponseWriter
	statusCode int
}

func newStatusWriter(w http.ResponseWriter) *statusWriter {
	return &statusWriter{w, http.StatusOK}
}

func (s *statusWriter) WriteHeader(code int) {
	s.statusCode = code
	s.ResponseWriter.WriteHeader(code)
}

func requestFields(req *http.Request) log.Fields {
	return log.Fields{
		"method": req.Method,
		"path":   req.URL.Path,
		"addr":   req.RemoteAddr,
	}
}

func loggingHandler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		statusWriter := newStatusWriter(w)
		handler.ServeHTTP(statusWriter, req)
		fields := log.Fields{
			"headers": w.Header(),
			"status":  statusWriter.statusCode,
		}
		log.WithFields(requestFields(req)).WithFields(fields).Infof("processed request")
	})
}
<commit_msg>Log successful requests at debug level rather than info (#103)<commit_after>// Copyright 2017 uSwitch
//
// 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 metadata

import (
	"net/http"

	log "github.com/sirupsen/logrus"
)

type statusWriter struct {
	http.ResponseWriter
	statusCode int
}

func newStatusWriter(w http.ResponseWriter) *statusWriter {
	return &statusWriter{w, http.StatusOK}
}

func (s *statusWriter) WriteHeader(code int) {
	s.statusCode = code
	s.ResponseWriter.WriteHeader(code)
}

func requestFields(req *http.Request) log.Fields {
	return log.Fields{
		"method": req.Method,
		"path":   req.URL.Path,
		"addr":   req.RemoteAddr,
	}
}

func loggingHandler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		statusWriter := newStatusWriter(w)
		handler.ServeHTTP(statusWriter, req)
		fields := log.Fields{
			"headers": w.Header(),
			"status":  statusWriter.statusCode,
		}
		logger := log.WithFields(requestFields(req)).WithFields(fields)
		if statusWriter.statusCode < 400 {
			logger.Debug("processed request")
		} else {
			logger.Info("processed request")
		}
	})
}
<|endoftext|>