Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 111-cli-expansion-stateful-behaviour-more-command-feedback
  • 120-integration-tests-fail
  • 138-making-gnmi-response-processing-more-error-tolerable
  • 140-refactor-pipelines
  • 156-a-setrequest-to-change-a-specific-path-of-an-ond-only-works-for-paths-with-string-values
  • 186-creating-a-device-based-on-plugin-or-csbi-is-not-possible
  • 195-requesting-changes-does-not-work-in-storemode-database
  • 223-database-pnd-store-is-missing-option-to-search-by-name
  • 225-adding-support-and-visualization-for-the-test-coverage2
  • 233-structs-like-loadeddevice-loadedsbi-loadedrole-loadeduser-are-never-passed-as-pointer
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules-govet
  • 246-implement-our-own-version-to-send-gnmi-requests
  • 258-deal-with-read-only-fields-in-yang
  • 282-refactoring-of-the-current-test-setup
  • 289-quantum-safe-communication-between-rabbitmq-and-sdn-controller
  • 291-lab-vm-for-arm64-apple
  • 296-related-existing-work-about-change-logic-for-yang-models
  • 320-deadline-and-cancellation-for-grpc-calls
  • 336-add-error-handling-for-mne-watching-if-the-provided-paths-do-not-exist
  • 349-integration-test-for-lab01
  • 350-applying-a-sdn-configuration-should-also-update-the-internal-configuration-of-managed-network
  • 351-link-shadowing-of-global-variables
  • 383-re-organize-comands-in-cli
  • 392-remove-renovate
  • PSD_VGU_Logging
  • add-backup-script
  • add-dockerignore
  • add-script-with-docker-stats
  • add-sr-linux-yang-models
  • add-support-for-mtls-in-plugins
  • allow-slashes-in-branch-names
  • arm-build
  • bump-ygot-generator-to-0-0-5
  • check-unit-tests
  • ci-refactor-1337
  • cli-docs
  • create-health-check-api
  • custom-marshal-for-grpc-gateway
  • deployment-docker-compose
  • develop
  • docker-build-cache-experiments
  • fbi1478-master-patch-42436
  • fix-docker-registry-error
  • fix-linting-in-makefile
  • fix-viper
  • go-plugin-playground
  • gosdn-storage-cleanup
  • heiss_bachelor_thesis
  • hotfix-unique-list-error-from-a-device-get-request
  • integration-test-pipeline-fix
  • inventory-manager-netbox
  • istaester/add-git-hooks
  • istaester/architecture-figures
  • istaester/basic-persistance-layer
  • istaester/bump-ygot-version
  • istaester/cli-tests
  • istaester/db
  • istaester/handle-makefile-in-editorconfig
  • istaester/init-monorepo
  • istaester/plugin-registry
  • istaester/provide-pnd-service
  • istaester/tooling
  • istaester/update-readme
  • master
  • mb/plugin-registry
  • mk/benchmark-stores
  • mpsd-at-vgu
  • neil/cobra-tests
  • new-integration-test-setup-v1
  • profile
  • proto-getters
  • recursive-read-only-try-1337
  • registry-used-by-app
  • remove-stuff
  • renovate/babel-runtime-7.x-lockfile
  • renovate/buf.build-gen-go-bufbuild-protovalidate-protocolbuffers-go-1.x
  • renovate/dompurify-3.x-lockfile
  • renovate/eslint-9.x-lockfile
  • renovate/eslint-plugin-prettier-5.x-lockfile
  • renovate/eslint-plugin-react-7.x-lockfile
  • renovate/eslint-plugin-react-hooks-5.x-lockfile
  • renovate/eslint-plugin-react-refresh-0.x-lockfile
  • renovate/fortawesome-fontawesome-svg-core-6.x-lockfile
  • renovate/fortawesome-free-regular-svg-icons-6.x-lockfile
  • renovate/fortawesome-free-solid-svg-icons-6.x-lockfile
  • renovate/github.com-aristanetworks-goarista-digest
  • renovate/github.com-bufbuild-protovalidate-go-0.x
  • renovate/github.com-docker-docker-27.x
  • renovate/github.com-docker-docker-28.x
  • renovate/github.com-grpc-ecosystem-grpc-gateway-v2-2.x
  • renovate/github.com-hashicorp-go-plugin-1.x
  • renovate/github.com-lesismal-nbio-1.x
  • renovate/github.com-openconfig-gnmi-0.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/go.mongodb.org-mongo-driver-2.x
  • renovate/golangci-golangci-lint-1.x
  • renovate/google.golang.org-genproto-googleapis-api-digest
  • renovate/react-18.x-lockfile
  • renovate/react-bootstrap-2.x-lockfile
  • 0.1.0
101 results

Target

Select target project
  • danet/gosdn
1 result
Select Git revision
  • 111-cli-expansion-stateful-behaviour-more-command-feedback
  • 120-integration-tests-fail
  • 138-making-gnmi-response-processing-more-error-tolerable
  • 140-refactor-pipelines
  • 156-a-setrequest-to-change-a-specific-path-of-an-ond-only-works-for-paths-with-string-values
  • 186-creating-a-device-based-on-plugin-or-csbi-is-not-possible
  • 195-requesting-changes-does-not-work-in-storemode-database
  • 223-database-pnd-store-is-missing-option-to-search-by-name
  • 225-adding-support-and-visualization-for-the-test-coverage2
  • 233-structs-like-loadeddevice-loadedsbi-loadedrole-loadeduser-are-never-passed-as-pointer
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules-govet
  • 246-implement-our-own-version-to-send-gnmi-requests
  • 258-deal-with-read-only-fields-in-yang
  • 282-refactoring-of-the-current-test-setup
  • 289-quantum-safe-communication-between-rabbitmq-and-sdn-controller
  • 291-lab-vm-for-arm64-apple
  • 296-related-existing-work-about-change-logic-for-yang-models
  • 320-deadline-and-cancellation-for-grpc-calls
  • 336-add-error-handling-for-mne-watching-if-the-provided-paths-do-not-exist
  • 349-integration-test-for-lab01
  • 350-applying-a-sdn-configuration-should-also-update-the-internal-configuration-of-managed-network
  • 351-link-shadowing-of-global-variables
  • 383-re-organize-comands-in-cli
  • 392-remove-renovate
  • PSD_VGU_Logging
  • add-backup-script
  • add-dockerignore
  • add-script-with-docker-stats
  • add-sr-linux-yang-models
  • add-support-for-mtls-in-plugins
  • allow-slashes-in-branch-names
  • arm-build
  • bump-ygot-generator-to-0-0-5
  • check-unit-tests
  • ci-refactor-1337
  • cli-docs
  • create-health-check-api
  • custom-marshal-for-grpc-gateway
  • deployment-docker-compose
  • develop
  • docker-build-cache-experiments
  • fbi1478-master-patch-42436
  • fix-docker-registry-error
  • fix-linting-in-makefile
  • fix-viper
  • go-plugin-playground
  • gosdn-storage-cleanup
  • heiss_bachelor_thesis
  • hotfix-unique-list-error-from-a-device-get-request
  • integration-test-pipeline-fix
  • inventory-manager-netbox
  • istaester/add-git-hooks
  • istaester/architecture-figures
  • istaester/basic-persistance-layer
  • istaester/bump-ygot-version
  • istaester/cli-tests
  • istaester/db
  • istaester/handle-makefile-in-editorconfig
  • istaester/init-monorepo
  • istaester/plugin-registry
  • istaester/provide-pnd-service
  • istaester/tooling
  • istaester/update-readme
  • master
  • mb/plugin-registry
  • mk/benchmark-stores
  • mpsd-at-vgu
  • neil/cobra-tests
  • new-integration-test-setup-v1
  • profile
  • proto-getters
  • recursive-read-only-try-1337
  • registry-used-by-app
  • remove-stuff
  • renovate/babel-runtime-7.x-lockfile
  • renovate/buf.build-gen-go-bufbuild-protovalidate-protocolbuffers-go-1.x
  • renovate/dompurify-3.x-lockfile
  • renovate/eslint-9.x-lockfile
  • renovate/eslint-plugin-prettier-5.x-lockfile
  • renovate/eslint-plugin-react-7.x-lockfile
  • renovate/eslint-plugin-react-hooks-5.x-lockfile
  • renovate/eslint-plugin-react-refresh-0.x-lockfile
  • renovate/fortawesome-fontawesome-svg-core-6.x-lockfile
  • renovate/fortawesome-free-regular-svg-icons-6.x-lockfile
  • renovate/fortawesome-free-solid-svg-icons-6.x-lockfile
  • renovate/github.com-aristanetworks-goarista-digest
  • renovate/github.com-bufbuild-protovalidate-go-0.x
  • renovate/github.com-docker-docker-27.x
  • renovate/github.com-docker-docker-28.x
  • renovate/github.com-grpc-ecosystem-grpc-gateway-v2-2.x
  • renovate/github.com-hashicorp-go-plugin-1.x
  • renovate/github.com-lesismal-nbio-1.x
  • renovate/github.com-openconfig-gnmi-0.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/go.mongodb.org-mongo-driver-2.x
  • renovate/golangci-golangci-lint-1.x
  • renovate/google.golang.org-genproto-googleapis-api-digest
  • renovate/react-18.x-lockfile
  • renovate/react-bootstrap-2.x-lockfile
  • 0.1.0
101 results
Show changes
Commits on Source (2)
renovate:
stage: tools
image: renovate/renovate:37.279.0
image: renovate/renovate:37.279.3
variables:
LOG_LEVEL: debug
......
......@@ -50,7 +50,7 @@ A description must be passed as positional argument.`,
Run: func(cmd *cobra.Command, args []string) {
spinner, _ := pterm.DefaultSpinner.Start("Creating new PND")
_, err := api.AddPnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), pndName, pndDescription)
_, err := api.CreatePnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), pndName, pndDescription)
if err != nil {
spinner.Fail("Failed creating the PND with name: ", pndName)
spinner.Fail(err)
......
......@@ -47,7 +47,7 @@ var pndListCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
spinner, _ := pterm.DefaultSpinner.Start("Fetching PND list from controller")
resp, err := api.GetPnds(createContextWithAuthorization(), pndAdapter.Endpoint())
resp, err := api.GetPndList(createContextWithAuthorization(), pndAdapter.Endpoint())
if err != nil {
spinner.Fail(err)
return
......
......@@ -55,7 +55,7 @@ func ensureStoreFileForTestsIsRemoved(storeName string) {
func Test_AddPnd(t *testing.T) {
defer ensureFilesForTestsAreRemoved()
resp, err := AddPnd(context.TODO(), bufnet, "test", "test pnd")
resp, err := CreatePnd(context.TODO(), bufnet, "test", "test pnd")
if err != nil {
t.Error(err)
return
......
package api
import (
"context"
"time"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/app"
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/client"
)
// Register checks if the app already exists and if not creates a new one.
func Register(ctx context.Context, addr, appname, token string) (*apb.AppRegisterResponse, error) {
appClient, err := nbi.AppClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &apb.AppRegisterRequest{
Timestamp: time.Now().UnixNano(),
Appname: appname,
Token: token,
}
return appClient.Register(ctx, req)
}
// Deregister deregisters an app.
func Deregister(ctx context.Context, addr, appname, token string) (*apb.AppDeregisterResponse, error) {
appClient, err := nbi.AppClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &apb.AppDeregisterRequest{
Timestamp: time.Now().UnixNano(),
Appname: appname,
}
return appClient.Deregister(ctx, req)
}
package api
import (
"context"
"time"
cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/configurationmanagement"
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/client"
)
// ExportSDNConfig returns the SDN configuration.
func ExportSDNConfig(ctx context.Context, addr, pid string) (*cpb.ExportSDNConfigResponse, error) {
configClient, err := nbi.ConfigurationManagementClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &cpb.ExportSDNConfigRequest{
Timestamp: time.Now().UnixNano(),
Pid: pid,
}
return configClient.ExportSDNConfig(ctx, req)
}
// ImportSDNConfig receives an SDN configuration and imports it.
func ImportSDNConfig(ctx context.Context, addr, pid, sdnConfigData string) (*cpb.ImportSDNConfigResponse, error) {
configClient, err := nbi.ConfigurationManagementClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &cpb.ImportSDNConfigRequest{
Timestamp: time.Now().UnixNano(),
Pid: pid,
SdnConfigData: sdnConfigData,
}
return configClient.ImportSDNConfig(ctx, req)
}
......@@ -2,19 +2,15 @@ package api
import (
"context"
"errors"
"io"
"time"
"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict"
mnepb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement"
pipb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/plugin-internal"
spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/client"
"github.com/google/uuid"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ygot"
log "github.com/sirupsen/logrus"
)
......@@ -50,6 +46,23 @@ func AddNetworkElement(ctx context.Context, addr, mneName, mneUUID string, opt *
return client.AddList(ctx, req)
}
// AddNetworkElementList adds all the network elements to the controller. The name of each network element is optional.
// If no name is provided a name will be generated upon network element creation.
func AddNetworkElementList(ctx context.Context, addr, pid string, mneList []*mnepb.SetMne) (*mnepb.AddListResponse, error) {
client, err := nbi.NetworkElementClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &mnepb.AddListRequest{
Timestamp: time.Now().UnixNano(),
Mne: mneList,
Pid: pid,
}
return client.AddList(ctx, req)
}
// GetNetworkElement requests one network element belonging to a given
// PrincipalNetworkDomain from the controller. If no network element identifier
// is provided, an error is thrown.
......@@ -72,51 +85,19 @@ func GetNetworkElement(ctx context.Context, addr, pid string, mneid string) (*mn
return client.Get(ctx, req)
}
// GetPluginSchemaTree gets the schema tree for a plugin.
func GetPluginSchemaTree(ctx context.Context, addr string, pluginID uuid.UUID) (map[string]*yang.Entry, error) {
pluginClient, err := nbi.PluginClient(addr, dialOptions...)
// GetNetworkElements requests all available network elements related to one PND.
func GetNetworkElements(ctx context.Context, addr, pid string) (*mnepb.GetAllResponse, error) {
client, err := nbi.NetworkElementClient(addr, dialOptions...)
if err != nil {
return map[string]*yang.Entry{}, err
return nil, err
}
req := &pipb.GetPluginSchemaRequest{
req := &mnepb.GetAllRequest{
Timestamp: time.Now().UnixNano(),
Pid: pluginID.String(),
}
ctx, cancel := context.WithTimeout(ctx, time.Minute*10)
defer cancel()
sClient, err := pluginClient.GetPluginSchema(ctx, req)
if err != nil {
return map[string]*yang.Entry{}, err
}
sTreeBytes := []byte{}
for {
payload, err := sClient.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
log.Error(err)
closeErr := sClient.CloseSend()
if closeErr != nil {
return nil, err
}
return map[string]*yang.Entry{}, err
}
sTreeBytes = append(sTreeBytes, payload.Chunk...)
}
sTreeMap, err := ygot.GzipToSchema(sTreeBytes)
if err != nil {
return map[string]*yang.Entry{}, err
Pid: pid,
}
return sTreeMap, nil
return client.GetAll(ctx, req)
}
// GetFlattenedNetworkElement requests a network elements belonging to a given
......@@ -218,3 +199,28 @@ func DeleteNetworkElement(ctx context.Context, addr, pid, mneid string) (*mnepb.
return client.Delete(ctx, req)
}
// UpdateNetworkElement changes the metadata of the network element which is stored in the controller storage.
// Correct resource version needs to be provided to allow a change of the object in the storage.
func UpdateNetworkElement(ctx context.Context, addr, mneid, updatedName, updatedTransportAddress, updatedPid string, resourceVersion *conflict.Metadata) (*mnepb.UpdateNetworkElementResponse, error) {
client, err := nbi.NetworkElementClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &mnepb.UpdateNetworkElementRequest{
Timestamp: time.Now().UnixNano(),
NetworkElement: &mnepb.ManagedNetworkElement{
Id: mneid,
Name: updatedName,
TransportAddress: updatedTransportAddress,
TransportOption: &tpb.TransportOption{
Address: updatedTransportAddress,
},
Metadata: resourceVersion,
AssociatedPnd: updatedPid,
},
}
return client.Update(ctx, req)
}
......@@ -2,11 +2,18 @@ package api
import (
"context"
"errors"
"io"
"time"
pib "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/plugin-internal"
pipb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/plugin-internal"
prb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/plugin-registry"
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/client"
"github.com/google/uuid"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ygot"
"github.com/sirupsen/logrus"
)
// GetAvailablePlugins requests all available plugins that can be registered
......@@ -24,3 +31,50 @@ func GetAvailablePlugins(ctx context.Context, addr string) (*prb.GetResponse, er
return pluginRegistryClient.AvailablePlugins(ctx, req)
}
// GetPluginSchemaTree gets the schema tree for a plugin.
func GetPluginSchemaTree(ctx context.Context, addr string, pluginID uuid.UUID) (map[string]*yang.Entry, error) {
pluginClient, err := nbi.PluginClient(addr, dialOptions...)
if err != nil {
return map[string]*yang.Entry{}, err
}
req := &pipb.GetPluginSchemaRequest{
Timestamp: time.Now().UnixNano(),
Pid: pluginID.String(),
}
ctx, cancel := context.WithTimeout(ctx, time.Minute*10)
defer cancel()
sClient, err := pluginClient.GetPluginSchema(ctx, req)
if err != nil {
return map[string]*yang.Entry{}, err
}
sTreeBytes := []byte{}
for {
payload, err := sClient.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
logrus.Error(err)
closeErr := sClient.CloseSend()
if closeErr != nil {
return nil, err
}
return map[string]*yang.Entry{}, err
}
sTreeBytes = append(sTreeBytes, payload.Chunk...)
}
sTreeMap, err := ygot.GzipToSchema(sTreeBytes)
if err != nil {
return map[string]*yang.Entry{}, err
}
return sTreeMap, nil
}
......@@ -9,9 +9,9 @@ import (
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/client"
)
// AddPnd takes a name, description and SBI UUID to create a new
// CreatePnd takes an address, a name and a description to create a new
// PrincipalNetworkDomain on the controller.
func AddPnd(ctx context.Context, addr, name, description string) (*ppb.CreatePndListResponse, error) {
func CreatePnd(ctx context.Context, addr, name, description string) (*ppb.CreatePndListResponse, error) {
pndClient, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
......@@ -30,6 +30,21 @@ func AddPnd(ctx context.Context, addr, name, description string) (*ppb.CreatePnd
return pndClient.CreatePndList(ctx, req)
}
// CreatePndList uses the provided creation properties to add all the PNDs to the controller.
func CreatePndList(ctx context.Context, addr string, pnds []*ppb.PndCreateProperties) (*ppb.CreatePndListResponse, error) {
pndClient, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &ppb.CreatePndListRequest{
Timestamp: time.Now().UnixNano(),
Pnd: pnds,
}
return pndClient.CreatePndList(ctx, req)
}
// GetPnd requests one PrincipalNetworkDomain from the
// controller.
func GetPnd(ctx context.Context, addr string, args string) (*ppb.GetPndResponse, error) {
......@@ -48,9 +63,9 @@ func GetPnd(ctx context.Context, addr string, args string) (*ppb.GetPndResponse,
return pndClient.GetPnd(ctx, req)
}
// GetPnds requests all PrincipalNetworkDomains from the
// GetPndList requests all PrincipalNetworkDomains from the
// controller.
func GetPnds(ctx context.Context, addr string, args ...string) (*ppb.GetPndListResponse, error) {
func GetPndList(ctx context.Context, addr string, args ...string) (*ppb.GetPndListResponse, error) {
pndClient, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
......
package client
import (
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/app"
"google.golang.org/grpc"
)
// AppClient returns a client for the gRPC App service. It takes
// the address of the gRPC endpoint and optional grpc.DialOption
// as argument.
func AppClient(addr string, opts ...grpc.DialOption) (apb.AppServiceClient, error) {
conn, err := grpc.Dial(addr, opts...)
if err != nil {
return nil, err
}
return apb.NewAppServiceClient(conn), nil
}
package client
import (
cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/configurationmanagement"
"google.golang.org/grpc"
)
// ConfigurationManagementClient returns a client for the gRPC ConfigurationManagement service. It takes
// the address of the gRPC endpoint and optional grpc.DialOption
// as argument.
func ConfigurationManagementClient(addr string, opts ...grpc.DialOption) (cpb.ConfigurationManagementServiceClient, error) {
conn, err := grpc.Dial(addr, opts...)
if err != nil {
return nil, err
}
return cpb.NewConfigurationManagementServiceClient(conn), nil
}
......@@ -663,7 +663,7 @@ func (n *NetworkElementServer) addMne(ctx context.Context,
}
if mne.IsTransportValid() {
err = n.initialNetworkElementRootPathRequest(ctx, mne, plugin)
err = n.initialNetworkElementRootPathRequest(ctx, mne)
if err != nil {
return uuid.Nil, err
}
......@@ -692,7 +692,7 @@ func (n *NetworkElementServer) addMne(ctx context.Context,
return mne.ID(), nil
}
func (n *NetworkElementServer) initialNetworkElementRootPathRequest(ctx context.Context, mne networkelement.NetworkElement, plugin plugin.Plugin) error {
func (n *NetworkElementServer) initialNetworkElementRootPathRequest(ctx context.Context, mne networkelement.NetworkElement) error {
resp, err := n.getPath(ctx, mne, "/")
if err != nil {
return err
......
......@@ -59,14 +59,15 @@ func (t *FilesystemPndStore) readAllPndsFromFile() ([]networkdomain.LoadedPnd, e
// }
for i, loadedPND := range loadedPnds {
pndUUID, err := uuid.Parse(loadedPND.ID)
if err != nil {
return nil, err
}
newPnd := NewPND(
uuid.MustParse(loadedPND.ID),
pndUUID,
loadedPND.Name,
loadedPND.Description,
)
if err != nil {
return nil, err
}
pnds[i] = newPnd
}
......